Re: easy way to define pairs of setter and getter with blocks support

48 views
Skip to first unread message

Nick Sutterer

unread,
Apr 21, 2013, 5:12:28 AM4/21/13
to rubyonra...@googlegroups.com
Is that to provide blocks instead of methods in the controller?

On Friday, April 19, 2013 7:19:05 PM UTC+10, prin...@gmail.com wrote:
Hi there!

I was looking for some stuff that works like layout declaration in controllers:

class SomeController < ActionController::Base
  layout 'string'
  layout :method
  layout -> { 'from proc' }
end

What do you think about this:

require 'active_support/core_ext/array'

class Module
  protected
    def define_pair(setter, *args) # getter = setter, options = {}
      options = args.extract_options!
      getter  = args[0] || setter
      setter_visibility = options[:setter_visibility] || :protected
      getter_visibility = options[:getter_visibility] || :protected
      define_method getter do; end
      module_eval <<-RUBY, __FILE__, __LINE__ + 1
        def self.#{setter}(*args, &block)                                   # def self.layout(*args, &block)
          define_getter :#{getter}, :#{getter_visibility}, *args, &block    #   define_getter :_layout, :protected, *args, &block
        end                                                                 # end
                                                                            #
        #{setter_visibility} :#{setter}                                     # protected :layout
        #{getter_visibility} :#{getter}                                     # protected :_layout
      RUBY
    end

    def define_getter(name, visibility, *args, &block)
      arg = block_given? ? block : args[0]
      method_body = case arg
      when Proc
        helper_method = "_#{name}_from_proc" 
        define_method helper_method, &arg
        module_eval "#{visibility} :#{helper_method}"
        helper_method
      when Symbol
        arg
      else
        arg.inspect
      end
      module_eval <<-RUBY, __FILE__, __LINE__ + 1
        def #{name}               # def _layout
          #{method_body}          #   # dependent stuff
        end                       # end
        #{visibility} :#{name}    # protected :_layout
      RUBY
    end
end


# examples
module Test
  define_pair :smth

  smth do
    "from proc rand: #{Random.rand(1000)}"
  end

  def result
    smth
  end
end

class A
  include Test
end

class B
  define_pair :other_one

  other_one :method

  def method
    :from_method
  end

  def result
    other_one
  end
end

class C < B
end

class D < B
  other_one 'string'
end

puts "A: #{A.new.result}"
# A: from proc rand: 78
 
puts "A#2: #{A.new.result}"
#A#2: from proc rand: 380  
 
puts "B: #{B.new.result}"
#B: from_method 
 
puts "C: #{C.new.result}"
#C: from_method 
puts "D: #{D.new.result}"
 
#D: string 
 
It also can be replaced with method definitions, but one have to track methods visibility while redefining methods.
And it's also looks little prettier than method definition.

Here is temporary method names think we need decide new ones if you like the stuff.

prin...@gmail.com

unread,
Apr 22, 2013, 12:53:01 AM4/22/13
to rubyonra...@googlegroups.com
No, mostly for configuration purposes.

It can be useful in cases when you need something like class_attribute but you need to run a block in getter in instance context.
One can define method, but it would look less like metaprogramming.  And also if method should be with specified visibility, it's moved down to the right section, or one have to explicitly declare protected :method in every class where it's defined.

The most common example is ActiveController::Base::layout method.

воскресенье, 21 апреля 2013 г., 13:12:28 UTC+4 пользователь Nick Sutterer написал:

Nick Sutterer

unread,
Apr 23, 2013, 12:01:36 AM4/23/13
to rubyonra...@googlegroups.com
That's what I'm asking, something like

class UserController < ..
  layout do
    run_this_in_instance_ctx
  end

???

prin...@gmail.com

unread,
Apr 23, 2013, 12:56:19 AM4/23/13
to rubyonra...@googlegroups.com
yeah, but not only controllers - any class

вторник, 23 апреля 2013 г., 8:01:36 UTC+4 пользователь Nick Sutterer написал:
Reply all
Reply to author
Forward
0 new messages