|
View:
New views
10 Messages
—
Rating Filter:
Alert me
|
|
|
simple way to encapsulate class << self ; attr_accessor :xyz ; end?I'm writing some code which works in the context of a very popular Web
framework and yet bumps against limitations in that framework several times a day. One thing I have to do **constantly** is this: def foo class << bar attr_accessor :baz end do_stuff(bar.baz) end or sometimes even def foo instance_eval do class << self attr_accessor :bar end end do_stuff(bar) end This pattern gets ugly fast. It would be so much easier if I could just do foo.add_accessor(:bar) and get the same functionality as class << foo attr_accessor :bar end so I tried to graft this onto the base object: class BaseObject def add_methods(methods) class << self attr_accessor methods end end end But that blew up on me. There's two flaws in that. The first is that methods is already a method name, so using it as a variable name was a pretty dumb idea. The second is that the arg to the method isn't visible once you're inside that class << self block. It doesn't seem as if there's any way to do it without using #eval, and frankly, using #eval is so last month. Who uses #eval any more? That's like Fred Flintstone style. Nonetheless, here's how you can do it with eval: class Base def add_xsor(xsor) eval("class << self ; attr_accessor :#{xsor} ; end") end end class Boat < Base ; end boat = Boat.new boat.add_xsor(:need) boat.need = "bigger" The big flaw here, of course, is that it only works on instances, but in practical terms I always seem to use it in an instance context. I'm going to have to use this code for the time being but I'm definitely on the lookout for a better way to do it. It's clean, but not totally satisfying. -- Giles Bowkett Blog: http://gilesbowkett.blogspot.com Portfolio: http://www.gilesgoatboy.org Tumblelog: http://giles.tumblr.com/ |
|
|
Re: simple way to encapsulate class << self ; attr_accessor :xyz ; end?Alle venerdì 7 settembre 2007, Giles Bowkett ha scritto:
> I'm writing some code which works in the context of a very popular Web > framework and yet bumps against limitations in that framework several > times a day. One thing I have to do **constantly** is this: > > def foo > class << bar > attr_accessor :baz > end > do_stuff(bar.baz) > end > > or sometimes even > > def foo > instance_eval do > class << self > attr_accessor :bar > end > end > do_stuff(bar) > end > > This pattern gets ugly fast. It would be so much easier if I could just do > > foo.add_accessor(:bar) > > and get the same functionality as > > class << foo > attr_accessor :bar > end > > so I tried to graft this onto the base object: > > class BaseObject > def add_methods(methods) > class << self > attr_accessor methods > end > end > end > > But that blew up on me. There's two flaws in that. The first is that > methods is already a method name, so using it as a variable name was a > pretty dumb idea. The second is that the arg to the method isn't > visible once you're inside that class << self block. > > It doesn't seem as if there's any way to do it without using #eval, > and frankly, using #eval is so last month. Who uses #eval any more? > That's like Fred Flintstone style. > > Nonetheless, here's how you can do it with eval: > > class Base > def add_xsor(xsor) > eval("class << self ; attr_accessor :#{xsor} ; end") > end > end > > class Boat < Base ; end > boat = Boat.new > boat.add_xsor(:need) > boat.need = "bigger" > > The big flaw here, of course, is that it only works on instances, but > in practical terms I always seem to use it in an instance context. > > I'm going to have to use this code for the time being but I'm > definitely on the lookout for a better way to do it. It's clean, but > not totally satisfying. I'm not sure I understand correctly your problem. You could do this: class Base def add_xsor(*names) (class << self;self;end).class_eval{attr_reader *names)} end end This solves the problem of names not being visible in the body of the singleton class by using the fact that the return value of a class construct is the return value of the last expression (self, in this case). This allows to use the singleton class object in the context of def add_xsor, where names is visible. I hope this helps Stefano |
|
|
Re: simple way to encapsulate class << self ; attr_accessor :xyz ; end?2007/9/7, Giles Bowkett <gilesb@...>:
> I'm writing some code which works in the context of a very popular Web > framework and yet bumps against limitations in that framework several > times a day. This might be an indication that you are using the framework wrongly - or that it's the wrong framework for your task. > One thing I have to do **constantly** is this: > > def foo > class << bar > attr_accessor :baz > end > do_stuff(bar.baz) > end > > or sometimes even > > def foo > instance_eval do > class << self > attr_accessor :bar > end > end > do_stuff(bar) > end > > This pattern gets ugly fast. It would be so much easier if I could just do > > foo.add_accessor(:bar) > > and get the same functionality as > > class << foo > attr_accessor :bar > end > > so I tried to graft this onto the base object: > > class BaseObject > def add_methods(methods) > class << self > attr_accessor methods > end > end > end > > But that blew up on me. There's two flaws in that. The first is that > methods is already a method name, so using it as a variable name was a > pretty dumb idea. The second is that the arg to the method isn't > visible once you're inside that class << self block. > > It doesn't seem as if there's any way to do it without using #eval, There is: irb(main):001:0> class Object irb(main):002:1> def add_accessors(*names) irb(main):003:2> class<<self;self;end.class_eval { attr_accessor *names } irb(main):004:2> end irb(main):005:1> end => nil irb(main):006:0> x=Object.new => #<Object:0x7ff8602c> irb(main):007:0> x.add_accessors :foo, :bar => nil irb(main):008:0> x.foo=10 => 10 irb(main):009:0> x.bar => nil But there are other solutions as well: if you know the accessors beforehand you can do this module MyExtension attr_accessor :bar end ... some_object.extend MyExtension > and frankly, using #eval is so last month. Who uses #eval any more? > That's like Fred Flintstone style. > > Nonetheless, here's how you can do it with eval: <snip/> > I'm going to have to use this code for the time being but I'm > definitely on the lookout for a better way to do it. It's clean, but > not totally satisfying. See above. And probably rethink your framework usage. Kind regards robert |
|
|
Re: simple way to encapsulate class << self ; attr_accessor :xyz ; end?On 9/7/07, Giles Bowkett <gilesb@...> wrote:
> I'm writing some code which works in the context of a very popular Web > framework and yet bumps against limitations in that framework several > times a day. One thing I have to do **constantly** is this: > > def foo > class << bar > attr_accessor :baz > end > do_stuff(bar.baz) > end > > or sometimes even > > def foo > instance_eval do > class << self > attr_accessor :bar > end > end > do_stuff(bar) > end > > This pattern gets ugly fast. It would be so much easier if I could just do > > foo.add_accessor(:bar) > > and get the same functionality as > > class << foo > attr_accessor :bar > end > > so I tried to graft this onto the base object: > > class BaseObject > def add_methods(methods) > class << self > attr_accessor methods > end > end > end > > But that blew up on me. There's two flaws in that. The first is that > methods is already a method name, so using it as a variable name was a > pretty dumb idea. The second is that the arg to the method isn't > visible once you're inside that class << self block. > > It doesn't seem as if there's any way to do it without using #eval, > and frankly, using #eval is so last month. Who uses #eval any more? > That's like Fred Flintstone style. > > Nonetheless, here's how you can do it with eval: > > class Base > def add_xsor(xsor) > eval("class << self ; attr_accessor :#{xsor} ; end") > end > end > > class Boat < Base ; end > boat = Boat.new > boat.add_xsor(:need) > boat.need = "bigger" > > The big flaw here, of course, is that it only works on instances, but > in practical terms I always seem to use it in an instance context. > > I'm going to have to use this code for the time being but I'm > definitely on the lookout for a better way to do it. It's clean, but > not totally satisfying. > > -- > Giles Bowkett > > Blog: http://gilesbowkett.blogspot.com > Portfolio: http://www.gilesgoatboy.org > Tumblelog: http://giles.tumblr.com/ > > Hey, I had a bit of trouble following along cause it's late but I hope I got it right. You said that class << self attr_accessor :whatever end doesn't work. That's because you created a new class scope. The simple solution is to use the (class << self; self; end) idiom with class_eval or send. I prefer send but whatever. Anyway here's some mojo: class Object def add_methods(*methheads) methheads.each do |m| (class << self; self; end).send(:attr_accessor, m) end end end class Dog def initialize(name, age) @name, @age = name, age end end irb(main):014:0> d = Dog.new "Cobi", 2 => #<Dog:0x5cae4 @name="Cobi", @age=2> irb(main):015:0> d.name NoMethodError: undefined method `name' for #<Dog:0x5cae4 @name="Cobi", @age=2> from (irb):15 from :0 irb(main):016:0> d.add_methods :name, :age => [:name, :age] irb(main):017:0> d.name => "Cobi" irb(main):018:0> d.age => 2 I hope I understood what you were going for. Even if not that should get you started. If you want to add an attr_accessor to all instances, just use send on the class: Dog.send :attr_accessor, :name Pat |
|
|
Re: simple way to encapsulate class << self ; attr_accessor :xyz ; end?On Sep 7, 2:24 am, "Giles Bowkett" <gil...@...> wrote: > I'm writing some code which works in the context of a very popular Web > framework and yet bumps against limitations in that framework several > times a day. One thing I have to do **constantly** is this: > > def foo > class << bar > attr_accessor :baz > end > do_stuff(bar.baz) > end > > or sometimes even > > def foo > instance_eval do > class << self > attr_accessor :bar > end > end > do_stuff(bar) > end > > This pattern gets ugly fast. It would be so much easier if I could just do > > foo.add_accessor(:bar) > > and get the same functionality as > > class << foo > attr_accessor :bar > end > > so I tried to graft this onto the base object: > > class BaseObject > def add_methods(methods) > class << self > attr_accessor methods > end > end > end > > But that blew up on me. There's two flaws in that. The first is that > methods is already a method name, so using it as a variable name was a > pretty dumb idea. The second is that the arg to the method isn't > visible once you're inside that class << self block. > > It doesn't seem as if there's any way to do it without using #eval, > and frankly, using #eval is so last month. Who uses #eval any more? > That's like Fred Flintstone style. > > Nonetheless, here's how you can do it with eval: > > class Base > def add_xsor(xsor) > eval("class << self ; attr_accessor :#{xsor} ; end") > end > end > > class Boat < Base ; end > boat = Boat.new > boat.add_xsor(:need) > boat.need = "bigger" > > The big flaw here, of course, is that it only works on instances, but > in practical terms I always seem to use it in an instance context. > > I'm going to have to use this code for the time being but I'm > definitely on the lookout for a better way to do it. It's clean, but > not totally satisfying. module Kernel def meta class << self; self; end end end class Module public :attr_accessor, :attr_reader, :attr_writer end then def foo meta.attr_accessor :x end T. |
|
|
Re: simple way to encapsulate class << self ; attr_accessor :xyz ; end?> module Kernel
> def meta > class << self; self; end > end > end > > class Module > public :attr_accessor, :attr_reader, :attr_writer > end > > then > > def foo > meta.attr_accessor :x > end Out of several excellent alternatives to my code I think this is the most compelling. -- Giles Bowkett Blog: http://gilesbowkett.blogspot.com Portfolio: http://www.gilesgoatboy.org Tumblelog: http://giles.tumblr.com/ |
|
|
Re: simple way to encapsulate class << self ; attr_accessorGiles,
While you're at it, how about overloading >> to alias << in the context of class OPERATOR object, as the arrows are obviously pointing the wrong way as it stands :). (See my "dyslexic" posting on this forum - i.e. do a search on "dyslexic" and read my final posting for that thread. Ben -- Posted via http://www.ruby-forum.com/. |
|
|
Re: simple way to encapsulate class << self ; attr_accessorOn 9/8/07, Ben Tompkins <nbitspoken@...> wrote:
> Giles, > > While you're at it, how about overloading >> to alias << in the context > of > class OPERATOR object, as the arrows are obviously pointing the wrong > way as > it stands :). (See my "dyslexic" posting on this forum - i.e. do a > search on "dyslexic" and read my final posting for that thread. > Arrows? What arrows? Those are bitshift operators. Bitshift operators? What bitshift operators? Those are pairs of less than and greater than symbols. > Ben > > -- > Posted via http://www.ruby-forum.com/. > > |
|
|
Re: simple way to encapsulate class << self ; attr_accessor :xyz ; end?On Sep 7, 2007, at 7:52 PM, Giles Bowkett wrote: > > Out of several excellent alternatives to my code I think this is the > most compelling. i always define this in lib/rubyext.rb def singleton_class &b sc = class << self self end b ? module_eval(&b) : sc end then singleton_class.attr_accessor 'foo' or, better singleton_class do attr 'a' attr 'b' end it's a sin to define a method that has a compelling use for a block to silently ignore said block. another thing i use often is attributes, this lets you do this singleton_class do attribute 'foo' end which gives self.foo = 42 #=> @foo = 42 foo 42 #=> @foo = 42 foo #=> 42 foo? #=> true it's attr_accessor in steriods and a very very short lib. (gem install attributes) kind regards. a @ http://drawohara.com/ -- we can deny everything, except that we have the possibility of being better. simply reflect on that. h.h. the 14th dalai lama |
|
|
Re: simple way to encapsulate class << self ; attr_accessorThe point is that in this particular case, syntax doesn't just fail to
reflect but contradicts the semantics of the operation (i.e. "what it does"), perhaps in favor of an implementation perspective ("how it works"). Ben Logan Capaldo wrote: > On 9/8/07, Ben Tompkins <nbitspoken@...> wrote: >> Giles, >> >> While you're at it, how about overloading >> to alias << in the context >> of >> class OPERATOR object, as the arrows are obviously pointing the wrong >> way as >> it stands :). (See my "dyslexic" posting on this forum - i.e. do a >> search on "dyslexic" and read my final posting for that thread. >> > Arrows? What arrows? Those are bitshift operators. > Bitshift operators? What bitshift operators? Those are pairs of less > than and greater than symbols. -- Posted via http://www.ruby-forum.com/. |
| Free embeddable forum powered by Nabble | Forum Help |