Using a block to configure/initialize a class

Hi! i need a solution for this, it's pretty simple but i can't get it to
work...

suppose:

class Options

  def self.define_an_option
    # ...don't-know-how-implementation :frowning:
  end

  define_an_option :option1, String
  define_an_option :option2, Array
end

Then, i want to do something like this:

opt= Options.new
opt.option1 => ""
opt.option2 => []

opt.option1 do |o|
  o= "Hello"
end

opt.option2 do |o|
  o << 10
end

options.option1 => "Hello"
options.option2 => [10]

Thats all! Seems pretty simple, but i tried with a lot of variants and I
don't get it to work. Any ideas?

Thanks!

···

--
Posted via http://www.ruby-forum.com/.

Emmanuel Oga

Hi! i need a solution for this, it's pretty simple but i can't get it to
work...

suppose:

class Options

def self.define_an_option
   # ...don't-know-how-implementation :frowning:
end

define_an_option :option1, String
define_an_option :option2, Array
end

Then, i want to do something like this:

opt= Options.new
opt.option1 => ""
opt.option2 =>

opt.option1 do |o|
o= "Hello"
end

opt.option2 do |o|
o << 10
end

options.option1 => "Hello"
options.option2 => [10]

Before you do it, you should understand your API examples seems unnatural.

Why not to do

opt.option1 = "Hello"
opt.option2 << 10

?

Than, this example:

opt.option1 do |o|
  o = "Hello"
end

is almost impossible to do (possible, but hard), because it should read
like: "pass reference option value into block though 'o' variable; replace
'o' with reference to 'Hello' string" - option value will left untouched.

V.

···

From: list-bounce@example.com [mailto:list-bounce@example.com] On Behalf Of
Sent: Wednesday, September 26, 2007 1:09 AM

Hi --

Hi! i need a solution for this, it's pretty simple but i can't get it to
work...

suppose:

class Options

def self.define_an_option
   # ...don't-know-how-implementation :frowning:
end

define_an_option :option1, String
define_an_option :option2, Array
end

Then, i want to do something like this:

opt= Options.new
opt.option1 => ""
opt.option2 =>

opt.option1 do |o|
o= "Hello"
end

That's just a re-assignment to the variable 'o'. It's not going to
have any impact on opt.option1.

opt.option2 do |o|
o << 10
end

options.option1 => "Hello"
options.option2 => [10]

Thats all! Seems pretty simple, but i tried with a lot of variants and I
don't get it to work. Any ideas?

The block syntax seems a little odd. Is there any reason not to just
use attr_accessor? If you want it to default to a new instance of some
specific class, you could do something like:

class Options

   def self.define_an_option(name, klass)
     attr_writer name
     iv = "@#{name}"
     define_method(name) do
       unless instance_variables.include?(iv)
         instance_variable_set(iv, klass.new)
       end
       val = instance_variable_get(iv)
       yield val if block_given? # if you really need this
       val
     end
   end

   define_an_option :option1, String
   define_an_option :option2, Array
end

(and I suspect there are other versions of attr_reader with a default
value out there somewhere).

David

···

On Wed, 26 Sep 2007, Emmanuel Oga wrote:

--
Upcoming training from Ruby Power and Light, LLC:
   * Intro to Ruby on Rails, Edison, NJ, October 23-26
   * Advancing with Rails, Edison, NJ, November 6-9
Both taught by David A. Black.
See http://www.rubypal.com for more info!

Have you looked at the built-in class Struct? I think it will supply what you need.

<code>
Options = Struct.new(:option1, :option2)
opt=Options.new("", )
opt.option1 = "Hello"
opt.option2 << 10 << 42
opt.option1 # => "Hello"
opt.option2 # => [10, 42]
</code>

Regards, Morton

···

On Sep 25, 2007, at 6:09 PM, Emmanuel Oga wrote:

Hi! i need a solution for this, it's pretty simple but i can't get it to
work...

suppose:

class Options

  def self.define_an_option
    # ...don't-know-how-implementation :frowning:
  end

  define_an_option :option1, String
  define_an_option :option2, Array
end

Then, i want to do something like this:

opt= Options.new
opt.option1 => ""
opt.option2 =>

opt.option1 do |o|
  o= "Hello"
end

opt.option2 do |o|
  o << 10
end

options.option1 => "Hello"
options.option2 => [10]

Thats all! Seems pretty simple, but i tried with a lot of variants and I
don't get it to work. Any ideas?

Hi! thanks for you replies. I'm going to analyze them. For the moment i
wanted to answer the question of the unnatural api. The reason i wan't
to do it that way is because i'm not going to use String or array for
most of the options, but Structs. So i want a way to let the user do
this

Struct.new "Value", :sub1, :sub2, :sub3 << In fact, the user may not
even know about the Struct::Value class.

class Options
...same as before...
define_option :an_option
end

opt= Options.new

opt.an_option do |o|
o.sub1= ...
o.sub2= ...
o.sub3= ...
end

instead of

an_option.sub1= ...
an_option.sub2= ...
an_option.sub3= ...

···

--
Posted via http://www.ruby-forum.com/.

Emmanuel Oga

Hi! thanks for you replies. I'm going to analyze them. For the moment i
wanted to answer the question of the unnatural api. The reason i wan't
to do it that way is because i'm not going to use String or array for
most of the options, but Structs. So i want a way to let the user do
this

Struct.new "Value", :sub1, :sub2, :sub3 << In fact, the user may not
even know about the Struct::Value class.

class Options
...same as before...
define_option :an_option
end

opt= Options.new

opt.an_option do |o|
o.sub1= ...
o.sub2= ...
o.sub3= ...
end

instead of

an_option.sub1= ...
an_option.sub2= ...
an_option.sub3= ...
--

Acceptable explanation. Then, trying to answer:

1. Defining the method you need "by hands":

class Option
  def an_option
    @an_option ||= Value.new
    yield @an_option if block_given?
    @an_option
  end
end

2. Designing #define_option

class Option
  def self.define_option(name, type)
     class_eval %Q{
      def #{name}
        @#{name} ||= #{type.inspect}.new
        yield @#{name} if block_given?
        @#{name}
      end
     }
  end

  define_option :an_option, Array
end

o = Option.new

p o.an_option # =>

o.an_option { |opt|
  opt << 1 << 2 << 3
}

p o.an_option # => [1,2,3]

Really, I think it can be done with more grace (without textual eval).

V.

···

From: list-bounce@example.com [mailto:list-bounce@example.com] On Behalf Of
Sent: Wednesday, September 26, 2007 2:51 AM