I have just finished to migrate all my pet projects to GitHub: http://github.com/smartrics. In there you'll also find some of the forks I have made to stuff that I have modified.
I find GitHub easier to play with (albeit git is horribly more complicated than svn) and I like some of its features.
The projects in Google Code are now here:
* Rest Fixture: http://github.com/smartrics/RestFixture
* Pic Builder: http://github.com/smartrics/PicBuilder
* Rest Client: http://github.com/smartrics/RestClient
* JMeter Rest Sampler: http://github.com/smartrics/JMeterRestSampler
So, bye bye Google Code and thanks for the hospitality!
Saturday, 31 July 2010
Wednesday, 16 June 2010
Thursday, 3 June 2010
Lost in metaprogramming
More often than not, making heavy use of meta-programming, will get you into trouble. Especially when nasty side effects kick in and exceptions raise when they shouldn't. Clearly, analysis of the stack trace is rather pointless.
Then, sometimes, defining
UPDATE
another interesting gem for this purpose is Unroller
Then, sometimes, defining
set_trace_func
comes handy:
set_trace_func lambda { |event, file, line, id, binding, classname|
if(event=="raise")
puts "=" * 40
puts "%8s :%-2d %5s %8s" % [event, line, id, classname]
end
}
UPDATE
another interesting gem for this purpose is Unroller
Labels:
metaprogramming,
ruby,
set_trace_func
Thursday, 22 April 2010
Method chaining with Ruby
Implementing method chaining in Ruby is a bit fiddly. Let's, for example and without loss of generality, look at plain data holders: objects whose sole existence in life is to hold some data.
Standard data holders, in Ruby, are easily defined using
produces
But it would be far better and more compact to be able to use method chaining, so to be able to write:
To achieve it, some Ruby metaprogramming is required. Jay Fields wrote an article some time ago providing an implementation that is not entirely satisfactory. His implementation differenciates between getters and setters and the example above would look like
It's possible to do better by doing:
which, undoubtedly, will produce the desired output:
It could be neat, where appropriate, to add the
Extending the code is trivial. What the module all does is defining a method on the class
More complicated logic can be implemented to allow more than one input or provide only getters for calculated attributes.
This technique can also be used to go beyond simple data holders, towards fluid interfaces.
But all that is left as an exercise to the reader.
Standard data holders, in Ruby, are easily defined using
attr_accessor
s. For example:
class Person
attr_accessor :name, :surname
end
person = Person.new
person.name = "Bob"
person.surname = "Smith"
p person.name
p person
produces
"Bob"
#<person:0xb78925a8 surname="Smith" name="Bob">
But it would be far better and more compact to be able to use method chaining, so to be able to write:
person = Person.new.name("Bob").surname("Smith")
person.name
person.surname
To achieve it, some Ruby metaprogramming is required. Jay Fields wrote an article some time ago providing an implementation that is not entirely satisfactory. His implementation differenciates between getters and setters and the example above would look like
person = Person.new.set_name("Bob").set_surname("Smith")
person.name
person.surname
It's possible to do better by doing:
module MethodChain
def chained_attr_accessor(*names)
names.each do |name|
define_method :"#{name}" do | *args |
return instance_variable_get(:"@#{name}") if args.length == 0
if args.length == 1
instance_variable_set(:"@#{name}", args[0])
return self
end
raise ArgumentError.new("wrong number of arguments (#{args.length} for 1)")
end
end
end
end
class Person
extend MethodChain
chained_attr_accessor :name, :surname
end
person = Person.new
person.name("Bob").surname("Smith")
p person.name
p person
which, undoubtedly, will produce the desired output:
"Bob"
#<Person:0xb776ff40 @surname="Smith", @name="Bob">
It could be neat, where appropriate, to add the
chain_attr_accessor
to the Class
class, so that it's not even necessary to extend the class with the module:
class Class
def chained_attr_accessor(*names)
#...
end
end
class Person
# extend MethodChain
chained_attr_accessor :name, :surname
end
Conclusion
Extending the code is trivial. What the module all does is defining a method on the class
Person
with the name of the attribute. Each implementation checks the length of the arguments list and decided if behaving like a setter or a getter.More complicated logic can be implemented to allow more than one input or provide only getters for calculated attributes.
This technique can also be used to go beyond simple data holders, towards fluid interfaces.
But all that is left as an exercise to the reader.
Subscribe to:
Posts (Atom)