Something.new( :attribute => value) thing

Hello, I saw something very interesting in the code of FXRuby, and I
would like to use this kind of code in my scripts :

My_Window.new(app, “Button Test”, :opts => DECOR_ALL, :x => 100, :y =>
100)

I’m only able to do “classic” initialisations, such as :
My_Window.new(app, “Button Test”, DECOR_ALL, 100, 100)

What is the easiest way to create class which use the ":opts => … x =>
… y => " part ?
I’m sorry, I don’t know the name of this feature, so it’s quite
difficult to find informations about it.

I wrote a code to use for sample.

class My_Window

attr_accessor :application
attr_accessor :title

Do I have to create attributes ?

attr_accessor :opts
attr_accessor :x
attr_accessor :y

def initialize(application, title, ??? )

@application = application
@title = title

???

end

end

Thanks !

Marc-antoine Kruzik wrote:

What is the easiest way to create class which use the ":opts => … x =>
… y => " part ?
I’m sorry, I don’t know the name of this feature, so it’s quite
difficult to find informations about it.

When the trailing method arguments are key => value pairs, Ruby collects
them into a hash and passes the hash as the last argument to the method.
Frequently the keys are symbols such as :opts or :x. The keys don’t have
to be symbols, though.

See http://www.softiesonrails.com/2007/8/27/ruby-101-hashes-are-cool

On Sat, Sep 5, 2009 at 1:29 PM, Marc-antoine
Kruzik[email protected] wrote:

Hello, I saw something very interesting in the code of FXRuby, and I
would like to use this kind of code in my scripts :

My_Window.new(app, “Button Test”, :opts => DECOR_ALL, :x => 100, :y =>
100)

What is the easiest way to create class which use the ":opts => … x =>
… y => " part ?
I’m sorry, I don’t know the name of this feature, so it’s quite
difficult to find informations about it.

As Tim said, Ruby collects key-value pairs at the end of the argument
list as a Hash. Here’s an example:

irb(main):007:0> def test(a,b,c)
irb(main):008:1> p [a,b,c]
irb(main):009:1> p c.class
irb(main):010:1> c.each {|key,value| p [key,value]}
irb(main):011:1> end
=> nil
irb(main):012:0> test(1,2,:xxx => 5, :y => 55)
[1, 2, {:xxx=>5, :y=>55}]
Hash
[:xxx, 5]
[:y, 55]

Jesus.

Marc-antoine Kruzik wrote:

Do I have to create attributes ?

attr_accessor :opts
attr_accessor :x
attr_accessor :y

def initialize(application, title, ??? )

@application = application
@title = title

???

end

end

class A

def initialize(arg1, arg2, hash)
hash.each do |key, val|
A.send(:attr_accessor, key)
send("#{key}=", val)
end
end

end

a = A.new(“hello”, “world”, :x => 10, :y => 20, :z => “red”)
puts a.x
puts a.y
puts a.z

–output:–
10
20
red

a.x = “hello”
a.y = “goodbye”
a.z = “the end”

puts a.x
puts a.y
puts a.z

–output:–
hello
goodbye
the end

Tim H. wrote:

When the trailing method arguments are key => value pairs, Ruby collects
them into a hash and passes the hash as the last argument to the method.
Frequently the keys are symbols such as :opts or :x. The keys don’t have
to be symbols, though.

See http://www.softiesonrails.com/2007/8/27/ruby-101-hashes-are-cool

I know the hashes, but I didn’t know what was the best way to use
arguments this way (my first post). Nice link.

A.send(:attr_accessor, key)
send(“#{key}=”, val)

This solution is what I was looking for.
With a bit of work, I will be able to write code like this :

a = A.new(“hello”, “world”, :x => 10, :y => 20, :z => “red”)
a = A.new(“hello”, “world”, :z => “red”, :y => 20, :x => 10)
a = A.new(“hello”, “world”, :z => “red”)
a = A.new(“hello”, “world”, :x => 10)

Thank you very much, 7stud.

On Sun, 2009-09-06 at 03:06 +0900, Marc-antoine Kruzik wrote:

A.send(:attr_accessor, key)
send("#{key}=", val)

This solution is what I was looking for.
With a bit of work, I will be able to write code like this :

Hi Marc,

I’d try to keep it simple:

class A
def initialize(param_a, param_b, options = {})
@x = options[:x] || 50 # defaults to 50 if not specified
@y = options[:y] || 100
@z = options[:z] || ‘red’
puts “Initialized with #{@x}/#{@y}/#{@z}”
end
end

a = A.new(“hello”, “world”, :x => 10, :y => 20, :z => “red”)
Initialized with 10/20/red

a = A.new(“hello”, “world”, :z => “red”, :y => 20, :x => 10)
Initialized with 10/20/red

a = A.new(“hello”, “world”, :z => “red”)
Initialized with 50/100/red

a = A.new(“hello”, “world”, :x => 10)
Initialized with 10/100/red

  • Martin

Martin B. wrote:

On Sun, 2009-09-06 at 03:06 +0900, Marc-antoine Kruzik wrote:

A.send(:attr_accessor, key)
send(“#{key}=”, val)

This solution is what I was looking for.
With a bit of work, I will be able to write code like this :

Hi Marc,

I’d try to keep it simple:

class A
def initialize(param_a, param_b, options = {})
@x = options[:x] || 50 # defaults to 50 if not specified
@y = options[:y] || 100
@z = options[:z] || ‘red’
puts “Initialized with #{@x}/#{@y}/#{@z}”
end
end

Use default values is a goog idea. The problem is, you have to write the
code for @x, @y and @z.

My version is now this one :

I have three classes :
GUI_Object > GUI_Object_Graphic > Picture

The purpose of the code is to avoid to write a lot of code when you are
working on classes like Picture.

(I know, I don’t optimize my code, if you have better solution, it would
be nice.)

class GUI_Object

attr_accessor :parent

@accessors = [:parent]

def initialize(parent=nil, hash=nil)

@parent = parent

hash = param_hash_1(parent, hash)
modify_accessor(hash)

end

def param_hash_1(parent, hash)
if hash.is_a?(Hash)
return hash
elsif parent.is_a?(Hash)
@parent = nil
return parent
end
return nil
end

def modify_accessor(hash)
return if hash == nil
hash.each do |key, val|
if self.class.check_accessor(key) == true
# Here’s the 7stud function :
send(“#{key}=”, val)
else
raise(“unknown accessor for class #{self.class}: #{key}”)
end
end
end

def self.check_accessor(acc)
if self.accessor != nil and self.accessor.include?(acc)
return true
else
if self != GUI_Object
return true if self.ancestors[1].check_accessor(acc) == true
end
end
return false
end

def self.accessor
return @accessors
end

end

class GUI_Object_Graphic < GUI_Object

attr_reader :x
attr_reader :y
attr_accessor :width
attr_accessor :height

@accessors = [:x, :y, :width, :height]

def initialize(parent=nil, x=0, y=0, width=0, height=0, hash=nil)

@x = x
@y = y
@width = width
@height = height
hash = param_hash(x, y, width, height, hash)

@x = 0 if @x == nil
@y = 0 if @y == nil
@width = 0 if @width == nil
@height = 0 if @height == nil

super(parent, hash)

end

def param_hash(x, y, width, height, hash)
if hash.is_a?(Hash)
return hash
elsif x.is_a?(Hash)
@x = 0
return x
elsif y.is_a?(Hash)
@y = 0
return y
elsif width.is_a?(Hash)
@width = 0
return width
elsif height.is_a?(Hash)
@height = 0
return height
end
return nil
end

end

class Picture < GUI_Object_Graphic

attr_accessor :bg_color
attr_accessor :cadre
attr_accessor :marges
attr_accessor :image
attr_accessor :zoom

I ONLY have to create THIS list to use the attributes I want

@accessors = [:bg_color, :picture, :zoom]

So, it’s really, really not difficult

def initialize(parent=nil, x=0, y=0, width=0, height=0, hash=nil)

# Default values
@bg_color = nil
@zoom = 1


super

@marges = [0, 0, 0, 0]
@cadre = nil

end

end

So I can use these codes to create a Picture :

x = y = width = height = 0

a = Picture.new(nil, x, y, width, height)
a = Picture.new(nil, x, y, :zoom => 2, :width => 30, :bg_color => “red”)

I’m not using a class variable like @@accessors, because of the problems
with class variables.

With this code, people can easily create new classes like Picture. And
with a simple list like @accessors = [:bg_color, :picture, :zoom], they
can allow to use only the attributes they want.

It’s part of my code to create a super-easy-to-use GUI working with a
video game graphical library.
Here’s a screenshot :

I want the users able to create new components (such as Picture), so I
try to find the most easiest way.