Hi all,
Quick question: is there a better way to write Foo.contains below?
Forcing the lexical scoping like this feels wrong.
class Foo
def self.contains *o
@contents ||= []
@contents += o
contents = @contents
define_method(:contents) { contents }
end
end
class Bar < Foo
contains :goat, :boat
contains :stoat
end
p Bar.new.contents # => [:goat, :boat, :stoat]
Thanks!
William M. wrote:
Hi all,
Quick question: is there a better way to write Foo.contains below?
Forcing the lexical scoping like this feels wrong.
Maybe:
class Foo
def contents
self.class.contains
end
def self.contains *o
@contents ||= []
return @contents if o.empty?
@contents += o
end
end
class Bar < Foo
contains :goat, :boat
contains :stoat
end
p Bar.new.contents # => [:goat, :boat, :stoat]
T.
On 7/6/06, William M. [email protected] wrote:
define_method(:contents) { contents }
end
end
class Bar < Foo
contains :goat, :boat
contains :stoat
end
p Bar.new.contents # => [:goat, :boat, :stoat]
How about:
class Foo
class << self
def contains *o
@contents ||= []
@contents += o
end
attr_accessor :contents
end
def contents
@contents ||= self.class.contents
end
end
class Bar < Foo
contains :goat, :boat
contains :stoat
end
p Bar.new.contents #=> [:goat, :boat, :stoat]
On 7/7/06, Phil T. [email protected] wrote:
@contents += o
p Bar.new.contents # => [:goat, :boat, :stoat]
attr_accessor :contents
end
Phil
A tiny refinement (in the golfing mood):
class Foo
class << self
def contains(*args)
(@contents ||= []).push(*args)
end
end
def contents
self.class.contains
end
end
class Bar < Foo
contains :goat, :boat
contains :stoat
end
p Bar.contains
p Bar.new.contents
END
[:goat, :boat, :stoat]
[:goat, :boat, :stoat]
Regards,
Sean
On 7/6/06, Phil T. [email protected] wrote:
contents = @contents
end
def contents
@contents ||= self.class.contents
end
Actually, after thinking about it a bit more, I’d probably go with:
def contents
self.class.contents
end
end
Phil
2006/7/7, William M. [email protected]:
define_method(:contents) { contents }
end
end
Any reason why you cannot simply use a normal attribute accessor?
class Foo
class <<self
attr_reader :contents
def contains *o
(@contents ||= []).concat o
end
end
end
Note, you may want to use a Set to avoid duplicates.
Kind regards
robert
On Fri, 7 Jul 2006, William M. wrote:
define_method(:contents) { contents }
end
end
class Bar < Foo
contains :goat, :boat
contains :stoat
end
p Bar.new.contents # => [:goat, :boat, :stoat]
if the behaviour is useful - abstract it:
harp:~ > cat a.rb
module Container
module ClassMethods
def contents() @contents ||= [] end
def contains(*list) contents.push *list.flatten end
end
def contents() self.class.contents end
def self.included other
other.extend ClassMethods
super
end
end
class Foo
include Container
end
class Bar < Foo
contains :goat, :boat
contains :stoat
end
p Bar.new.contents # => [:goat, :boat, :stoat]
harp:~ > ruby a.rb
[:goat, :boat, :stoat]
regards.
-a
Excerpts from William M.'s mail of 6 Jul 2006 (PDT):
Quick question: is there a better way to write Foo.contains below?
Forcing the lexical scoping like this feels wrong.
Thanks for all the replies. A case of overlooking the obvious solution.