Is there a way to redefine []=+ in ruby - ruby

I am trying to write a simple DSL (against Redis) and I would like to define []+= myself
I have
def []=(key,val)
#redis.zadd(#name,val,key)
end
and I would like to define
def []+=(key,val)
#redis.zincrby(#name,val,key)
end
But my understanding is that Ruby provides the "[]+=" operator automaticallygiven []=
Is there a way to over-ride this behavior
Obviously I don't want this because I would not be able to, say, run this in pipeline mode

No, <operator>= can not be redefined in Ruby.
You can try to get really fancy and wrap your return values in classes that delegate to the actual value. This way, they behave like the actual value, but you can play tricks, for instance with +.
Here's a simple example:
require 'delegate'
module Redis
class Set
class Value < SimpleDelegator
def +(val)
Increment.new(self, val)
end
end
class Increment < SimpleDelegator
attr_reader :increment
def initialize(source, increment)
super(source.__getobj__ + increment)
#increment = increment
end
end
def [](key)
Value.new(#redis.not_sure_what(#name, key))
end
def []=(key,val)
if val.is_a?(Increment)
#redis.zincrby(#name,val.increment,key)
else
#redis.zadd(#name,val,key)
end
end
end
end
This is just a starting point. You'll have to be more careful than this, for example by checking the key is the same. In my simplistic example, redis[:foo] = redis[:bar] + 1 would actually be equivalent to redis[:foo] += 1...

Nope. x[y] += z expands to exactly x[y] = x[y] + z:
class << (object = Object.new)
def [](key)
puts "[#{key.inspect}]"
key
end
def []=(key, value)
puts "[#{key.inspect}] = #{value.inspect}"
value
end
end
# These are all equivalent
object['See?'] += " It's impossible."
object['See?'] = object['See?'] + " It's impossible."
object.[]=('See?', object.[]('See?').+(" It's impossible."))
# They all produce the same output:
# ["See?"]
# ["See?"] = "See? It's impossible."
# => "See? It's impossible."
You will have to create a separate method.

Related

Design pattern for a calculation that has to output a report in Ruby

I have a class that does calculations. Most of the times it is used in the code to output a single value:
Use: value = Calculator.new(1234).output
This is an example of the class definition:
class Calculator
def initialize(parameter_1)
#parameter_1 = parameter_1
end
def output
op_1_result = operation_1(#parameter_1)
op_2_result = operation_2(op_1_result)
operation_3(op_2_result)
end
def operation_1(param)
...
end
But sometimes the user has to print a report of the calculation, showing many of the variables from inside the calculations.
The first solution I implemented was to pass a parameter at initialization telling the class that it should save some internal variables for the report, like this:
class Calculator
attr_reader :report
def initialize(parameter_1, reporting=false)
#parameter_1 = parameter_1
#reporting = reporting
#report = {}
end
def output
op_1_result = operation_1(#parameter_1)
#report[:op_1_result] = op_1_result if #reporting
op_2_result = operation_2(op_1_result)
#report[:op_2_result] = op_2_result if #reporting
operation_3(op_2_result)
end
def operation_1(param)
...
end
Then, when I want to get those intermediate variables, I would:
calculator = Calculator.new(1234, true) # reporting activated
report = calculator.report
report[:op_1_result] # one of the intermediate variables of the calculation
Does this break the single responsibility principle, as the class is now calculating the value and reporting at the same time?
Is there a better way to do this, a design pattern where I could have a fast calculation of the output result where it is needed and show the report where needed without all those ifs?
Any light on this and comments will be really appreciated!
Obs (another discussion): I've read that a more functional approach to just outputting a value would be a great thing. But that kept me wondering about how to show those internal intermediate values when needed. How do more functional programmers would do it...?
I guess "builder pattern" is suitable and "report pad" should be injected from outside.
class Calculator
def initialize(*parameters)
#parameters = parameters
end
def report_to(report_pad)
#report_pad = report_pad
self
end
def output()
ret = #parameters[0].to_i + #parameters[1].to_i
report('Did p0 + p1')
ret
end
private
def report(message)
#report_pad << "\n".prepend(message) if #report_pad.respond_to? '<<'
end
end
####
reports = ""
result = Calculator
.new(1, 2)
.report_to(reports)
.output()
puts result, reports
Why don't you just make all intermediate results public methods and chain the results in the final output?
Perhaps something like this:
class Calculator
def initialize(parameter)
#parameter = parameter
end
def output
op_3_result
end
def op_1_result
#op_1_result ||= operation_1(parameter)
end
def op_2_result
#op_2_result ||= operation2(op_1_result)
end
def op_3_result
#op_3_result ||= operation3(op_2_result)
end
private
def operation1(arg)
# ...
end
def operation2(arg)
# ...
end
def operation3(arg)
# ...
end
attr_reader :parameter
end
That would allow you to call whatever you need on the same instance:
calculator = Calculator.new(1234)
calculator.output #=> the final result
calculator.op_2_result #=> the intermediate result of step 2
You could use a different pattern with Report being its own class and allow it to just pass through when reporting is turned off. Here is a simple example:
class Calculator
attr_reader :report
def initialize(parameter_1, reporting=false)
#parameter_1 = parameter_1
#report = Report.new(reporting)
end
def output
op1 = operation_1(report.capture(:param1,#parameter_1))
report.capture(:op1,op1)
op2 = report.capture(:op2) { operation_2(op1) }
operation_3(op2)
end
def operation_1(param);
param + 7
end
def operation_2(param);
param - 3
end
def operation_3(param);
param * 2
end
end
class Report
attr_reader :reporting, :reportables
def initialize(reporting)
#reporting = reporting
#reportables = {}
end
def capture(key, val=nil,&block)
warn "Block supercedes value" if val && block_given?
result = block_given? ? block.call : val
#reportables[key] = result if reporting
result
end
def [](key)
return 'No Reporting' unless reporting
#reportables[key]
end
end
Then you can use like so
c = Calculator.new(12)
c.output
#=> 32
c.report[:op1]
#=> "No Reporting"
c = Calculator.new(12, true)
c.output
#=> 32
c.report[:op1]
#=> 19
c.report[:param1]
#=> 12
This way each step can use a block for more complicated items where the result should be captured or just pass a value if you choose and intermediate steps like operation_3 (in this case) that do not need to be "captured" can just flow through.
If reporting is off then everything just flows through and the captures are ignored.
Your #output method could also look like this (no intermediate locals at all although it does hurt the readability a bit)
def output
operation_3 (
report.capture(:op2,
operation_2(
report.capture(:op1) do
operation_1(report.capture(:param1,#parameter_1))
end
)
)
)
end
You can use dependency injection like this:
class Calculator
def initialize(parameter_1, reporter = nil)
#parameter_1 = parameter_1
#reporter = reporter
end
def output
op_1_result = call_with_reporting :operation_1, #parameter_1
op_2_result = call_with_reporting :operation_2, op_1_result
operation_3(op_2_result)
end
def operation_1(param)
...
end
def call_with_reporting(operation, *args)
result = self.send(operation, *args)
#reporter.report(operation, result) if #reporter
result
end
end
class ConsoleReporter
def initialize
#results = {}
end
def report(operation, result)
#results[operation] = result
end
def run_report
puts #operations
end
end
Now you can use Calculator like this:
reporter = ConsoleReporter.new
Calculator.new(12, reporter).output
reporter.run_report
Later you can use Calculator with other format reporter (like ToFileReporter)

Assigning value to self in Ruby

I have the following class in Ruby:
class TOMatrix < Matrix
def initialize
self = Matrix.build(8, 8){|r, c| 0}
end
But, this gives the error:
Cannot assign to a keyword
Does anyone know how to achive what a I need ?
It seems you need to write a wrapper instead of subclassing the Matrix (subclassing in your case might break Liskov's substitution principle):
require 'matrix'
class TOMatrix
def initialize
#matrix = Matrix.build(8, 8){|r, c| 0}
end
def method_missing(*args, &block)
#matrix.send(*args, &block)
end
def respond_to?(method)
super || #matrix.respond_to?(method)
end
end
m = TOMatrix.new
m.hermitian? #=> true
You cannot change the value of self directly. You probably want to do something like this:
class Matrix # I defined it so that people can test the code right away
def initialize
#rows = []
self
end
def build rows = 0, columns = 0 #Use your own version of build instead
# It should modify Matrix instead of returning a new one
#rows = Array.new(rows, Array.new(columns, 0))
end
end
class TOMatrix < Matrix
def initialize
super.build 8, 8 #Initializes Matrix and calls build on it
end
end

Why isn't the puts method calling my .to_s method?

I thought that defining a to_s method for a custom class meant that calling the puts method on that class would return an output as specified by to_s. In this program, however, I only get the result I crave if I write puts bingo_board.to_s. What is going on?
class BingoBoard < Array
##letters = %w[B I N G O]
def initialize
# populates an 5x5 array with numbers 1-100
# to make this accessible across your methods within this class, I made
# this an instance variable. # = instance variable
#bingo_board = Array.new(5) {Array.new(5)}
#bingo_board.each_with_index do |column, i|
rangemin = 15 * i + 1
#bingo_board[i] = (rangemin..(rangemin+14)).to_a.sample(5)
end
#bingo_board[2][2] = "X" # the 'free space' in the middle
#game_over = false
end
def game_over?
#game_over
end
def generate_call
....
end
def compare_call(call)
#bingo_board[##letters.index(call[0])].include? call[1]
end
def react_to_call(call)
...
end
def check_board
...
end
def show_column(num)
...
end
def to_s
result = ""
0.upto(4) do |val|
result += " " + ##letters[val] + " "
end
result += "\n\n"
0.upto(4) do |row|
0.upto(4) do |col|
val = #bingo_board[col][row]
result += " " if val.to_i < 10
result += val.to_s + " "
end
result += "\n"
end
result
end
end
my_board = BingoBoard.new
counter = 0
until my_board.game_over?
puts my_board.to_s # renders the board in accordance with my to_s method
call = my_board.generate_call
counter += 1
puts "\nThe call \# #{counter} is #{call[0]} #{call[1]}"
my_board.react_to_call(call)
gets.chomp
end
puts my_board # renders bubkes (i.e., nothing)
puts "\n\n"
puts "Game over"
Its because you'r extending from Array. That's why you're getting the wierd behavior. I don't see where you need the extending from so just remove that and things will work as you expect.
Here's a more detaled answer if you'd like to know why this is happening. Basically puts makes an exception for arrays so when an array is passed puts is called on each member. Ruby Array#puts not using overridden implementation?
As #jörgwmittag said, this is a special case. The IO#puts method treats arrays - which means anything that responds to to_ary - differently. It calls to_ary first and then iterates over each element of the resulting array, and only calls to_s on them. It never calls to_s on the array itself.
If you delegate to a member array instead of subclassing from Array, you have finer-grained control over what gets "inherited" (delegated). Then you can exclude to_ary from the delegation, which will prevent puts from seeing your object as an Array and triggering this behavior.
Other general solutions:
Use string interpolation or explicit to_s calls so that what puts receives is already a string:
puts "#{bingo_board}"
puts bingo_board.to_s
Use print or printf instead of puts:
print bingo_board,"\n"
printf "%s\n",bingo_board
If the object is an Array or can be converted to one (i.e. it implements to_ary), then puts will not call to_s on the object, but rather iterate over the object and print each object within by calling to_s on it.
See:
puts [1, 2]
# 1
# 2
[1, 2].to_s
# => '[1, 2]'
This is actually documented, although somewhat implicitly:
If called with an array argument, writes each element on a new line.
Looks like it runs Array#inspect method instead of your custom to_s. Adding alias_method :inspect, :to_s just after ending of the to_s definition will help you.
But it'll work only with p, because puts runs each(&:inspect).

How to use Ruby mixins as patches to classes

I started looking into Ruby, since I am looking to a more dynamic alternative to Java.
I like how you can modify a class in Ruby after it's definition, for example like this:
class A
def print
"A"
end
end
class B < A
def print
super + "B"
end
end
class A
alias_method :print_orig, :print
def print
print_orig + "+"
end
end
puts B.new.print # A+B
Now I try to do the same with mixins:
class A
def print
"A"
end
end
class B < A
def print
super + "B"
end
end
module Plus
alias_method :print_orig, :print
def print
print_orig + "+"
end
end
A.extend(Plus) # variant 1
B.extend(Plus) # variant 2
class A # variant 3
include Plus
end
class B # variant 4
include Plus
end
puts B.new.print
However none of the variants produce the expected result. BTW, the expected result is the following: I want to be able to 'patch' class A with a mixin, in order to modify its behavior. I want to use mixins, since I want to 'patch' several classes with the same behavior.
Is it possible to do what I want? If yes, how?
Your module code doesn't work because it is executed in wrong context. You need to execute it in context of A, but it is instead evaluated in context of Plus. This means, you need to change self from Plus to A.
Observe:
class A
def print
"A"
end
end
class B < A
def print
super + "B"
end
end
module Plus
self # => Plus
def self.included base
self # => Plus
base # => A
base.class_eval do
self # => A
alias_method :print_orig, :print
def print
print_orig + "+"
end
end
end
end
A.send :include, Plus
B.new.print # => "A+B"
You can't really use Mixins in this way. You're generating a conflict between the class and its mixin. Mixins implicitly resolve the conflict by linearization. Bottom line is: In case of conflict, the class's method is preferred over the mixin. To fix that, you can use Sergio' Tulentsev's approach and have the mixin change its base class aggressively.
Or, you can add methods reflectively. Consider this example, which I've stolen from Mark's blog.
class Talker
[:hello, :good_bye].each do |arg|
method_name = ("say_" + arg.to_s).to_sym
send :define_method, method_name do
puts arg
end
end
end
t = Talker.new
t.say_hello
t.say_good_bye

How to implement a "callback" in Ruby?

I'm not sure of the best idiom for C style call-backs in Ruby - or if there is something even better ( and less like C ). In C, I'd do something like:
void DoStuff( int parameter, CallbackPtr callback )
{
// Do stuff
...
// Notify we're done
callback( status_code )
}
Whats a good Ruby equivalent? Essentially I want to call a passed in class method, when a certain condition is met within "DoStuff"
The ruby equivalent, which isn't idiomatic, would be:
def my_callback(a, b, c, status_code)
puts "did stuff with #{a}, #{b}, #{c} and got #{status_code}"
end
def do_stuff(a, b, c, callback)
sum = a + b + c
callback.call(a, b, c, sum)
end
def main
a = 1
b = 2
c = 3
do_stuff(a, b, c, method(:my_callback))
end
The idiomatic approach would be to pass a block instead of a reference to a method. One advantage a block has over a freestanding method is context - a block is a closure, so it can refer to variables from the scope in which it was declared. This cuts down on the number of parameters do_stuff needs to pass to the callback. For instance:
def do_stuff(a, b, c, &block)
sum = a + b + c
yield sum
end
def main
a = 1
b = 2
c = 3
do_stuff(a, b, c) { |status_code|
puts "did stuff with #{a}, #{b}, #{c} and got #{status_code}"
}
end
This "idiomatic block" is a very core part of everyday Ruby and is covered frequently in books and tutorials. The Ruby information section provides links to useful [online] learning resources.
The idiomatic way is to use a block:
def x(z)
yield z # perhaps used in conjunction with #block_given?
end
x(3) {|y| y*y} # => 9
Or perhaps converted to a Proc; here I show that the "block", converted to a Proc implicitly with &block, is just another "callable" value:
def x(z, &block)
callback = block
callback.call(z)
end
# look familiar?
x(4) {|y| y * y} # => 16
(Only use the above form to save the block-now-Proc for later use or in other special cases as it adds overhead and syntax noise.)
However, a lambda can be use just as easily (but this is not idiomatic):
def x(z,fn)
fn.call(z)
end
# just use a lambda (closure)
x(5, lambda {|y| y * y}) # => 25
While the above approaches can all wrap "calling a method" as they create closures, bound Methods can also be treated as first-class callable objects:
class A
def b(z)
z*z
end
end
callable = A.new.method(:b)
callable.call(6) # => 36
# and since it's just a value...
def x(z,fn)
fn.call(z)
end
x(7, callable) # => 49
In addition, sometimes it's useful to use the #send method (in particular if a method is known by name). Here it saves an intermediate Method object that was created in the last example; Ruby is a message-passing system:
# Using A from previous
def x(z, a):
a.__send__(:b, z)
end
x(8, A.new) # => 64
Happy coding!
Explored the topic a bit more and updated the code.
The following version is an attempt to generalize the technique, although remaining extremely simplified and incomplete.
I largely stole - hem, found inspiration in - the implementation of callbacks of DataMapper, which seems to me quite complete and beatiful.
I strongly suggest to have a look at the code # http://github.com/datamapper/dm-core/blob/master/lib/dm-core/support/hook.rb
Anyway, trying to reproduce the functionality using the Observable module was quite engaging and instructive.
A few notes:
method added seems to be require because the original instance methods are not available at the moment of registering the callbacks
the including class is made both observed and self-observer
the example is limited to the instance methods, does not support blocks, args and so on
code:
require 'observer'
module SuperSimpleCallbacks
include Observable
def self.included(klass)
klass.extend ClassMethods
klass.initialize_included_features
end
# the observed is made also observer
def initialize
add_observer(self)
end
# TODO: dry
def update(method_name, callback_type) # hook for the observer
case callback_type
when :before then self.class.callbacks[:before][method_name.to_sym].each{|callback| send callback}
when :after then self.class.callbacks[:after][method_name.to_sym].each{|callback| send callback}
end
end
module ClassMethods
def initialize_included_features
#callbacks = Hash.new
#callbacks[:before] = Hash.new{|h,k| h[k] = []}
#callbacks[:after] = #callbacks[:before].clone
class << self
attr_accessor :callbacks
end
end
def method_added(method)
redefine_method(method) if is_a_callback?(method)
end
def is_a_callback?(method)
registered_methods.include?(method)
end
def registered_methods
callbacks.values.map(&:keys).flatten.uniq
end
def store_callbacks(type, method_name, *callback_methods)
callbacks[type.to_sym][method_name.to_sym] += callback_methods.flatten.map(&:to_sym)
end
def before(original_method, *callbacks)
store_callbacks(:before, original_method, *callbacks)
end
def after(original_method, *callbacks)
store_callbacks(:after, original_method, *callbacks)
end
def objectify_and_remove_method(method)
if method_defined?(method.to_sym)
original = instance_method(method.to_sym)
remove_method(method.to_sym)
original
else
nil
end
end
def redefine_method(original_method)
original = objectify_and_remove_method(original_method)
mod = Module.new
mod.class_eval do
define_method(original_method.to_sym) do
changed; notify_observers(original_method, :before)
original.bind(self).call if original
changed; notify_observers(original_method, :after)
end
end
include mod
end
end
end
class MyObservedHouse
include SuperSimpleCallbacks
before :party, [:walk_dinosaure, :prepare, :just_idle]
after :party, [:just_idle, :keep_house, :walk_dinosaure]
before :home_office, [:just_idle, :prepare, :just_idle]
after :home_office, [:just_idle, :walk_dinosaure, :just_idle]
before :second_level, [:party]
def home_office
puts "learning and working with ruby...".upcase
end
def party
puts "having party...".upcase
end
def just_idle
puts "...."
end
def prepare
puts "preparing snacks..."
end
def keep_house
puts "house keeping..."
end
def walk_dinosaure
puts "walking the dinosaure..."
end
def second_level
puts "second level..."
end
end
MyObservedHouse.new.tap do |house|
puts "-------------------------"
puts "-- about calling party --"
puts "-------------------------"
house.party
puts "-------------------------------"
puts "-- about calling home_office --"
puts "-------------------------------"
house.home_office
puts "--------------------------------"
puts "-- about calling second_level --"
puts "--------------------------------"
house.second_level
end
# => ...
# -------------------------
# -- about calling party --
# -------------------------
# walking the dinosaure...
# preparing snacks...
# ....
# HAVING PARTY...
# ....
# house keeping...
# walking the dinosaure...
# -------------------------------
# -- about calling home_office --
# -------------------------------
# ....
# preparing snacks...
# ....
# LEARNING AND WORKING WITH RUBY...
# ....
# walking the dinosaure...
# ....
# --------------------------------
# -- about calling second_level --
# --------------------------------
# walking the dinosaure...
# preparing snacks...
# ....
# HAVING PARTY...
# ....
# house keeping...
# walking the dinosaure...
# second level...
This simple presentation of the use of Observable could be useful: http://www.oreillynet.com/ruby/blog/2006/01/ruby_design_patterns_observer.html
So, this may be very "un-ruby", and I am not a "professional" Ruby developer, so if you guys are going to smack be, be gentle please :)
Ruby has a built-int module called Observer. I have not found it easy to use, but to be fair I did not give it much of a chance. In my projects I have resorted to creating my own EventHandler type (yes, I use C# a lot). Here is the basic structure:
class EventHandler
def initialize
#client_map = {}
end
def add_listener(id, func)
(#client_map[id.hash] ||= []) << func
end
def remove_listener(id)
return #client_map.delete(id.hash)
end
def alert_listeners(*args)
#client_map.each_value { |v| v.each { |func| func.call(*args) } }
end
end
So, to use this I expose it as a readonly member of a class:
class Foo
attr_reader :some_value_changed
def initialize
#some_value_changed = EventHandler.new
end
end
Clients of the "Foo" class can subscribe to an event like this:
foo.some_value_changed.add_listener(self, lambda { some_func })
I am sure this is not idiomatic Ruby and I am just shoehorning my C# experience into a new language, but it has worked for me.
If you are willing to use ActiveSupport (from Rails), you have a straightforward implementation
class ObjectWithCallbackHooks
include ActiveSupport::Callbacks
define_callbacks :initialize # Your object supprots an :initialize callback chain
include ObjectWithCallbackHooks::Plugin
def initialize(*)
run_callbacks(:initialize) do # run `before` callbacks for :initialize
puts "- initializing" # then run the content of the block
end # then after_callbacks are ran
end
end
module ObjectWithCallbackHooks::Plugin
include ActiveSupport::Concern
included do
# This plugin injects an "after_initialize" callback
set_callback :initialize, :after, :initialize_some_plugin
end
end
I know this is an old post, but I found it when tried to solve a similar problem.
It's a really elegant solution, and most importantly, it can work with and without a callback.
Let's say we have the Arithmetic class which implements basic operations on them — addition and subtraction.
class Arithmetic
def addition(a, b)
a + b
end
def subtraction(a, b)
a - b
end
end
And we want to add a callback for each operation which will do something with the input data and result.
In the below example we will implement the after_operation method which accepts the Ruby block which will be executed after an operation.
class Arithmetic
def after_operation(&block)
#after_operation_callback = block
end
def addition(a, b)
do_operation('+', a, b)
end
def subtraction(a, b)
do_operation('-', a, b)
end
private
def do_operation(sign, a, b)
result =
case sign
when '+'
a + b
when '-'
a - b
end
if callback = #after_operation_callback
callback.call(sign, a, b, result)
end
result
end
end
Using with callback:
callback = -> (sign, a, b, result) do
puts "#{a} #{sign} #{b} = #{result}"
end
arithmetic = Arithmetic.new
arithmetic.after_operation(&callback)
puts arithmetic.addition(1, 2)
puts arithmetic.subtraction(3, 1)
Output:
1 + 2 = 3
3
3 - 1 = 2
2
I often implement callbacks in Ruby like in the following example. It's very comfortable to use.
class Foo
# Declare a callback.
def initialize
callback( :on_die_cast )
end
# Do some stuff.
# The callback event :on_die_cast is triggered.
# The variable "die" is passed to the callback block.
def run
while( true )
die = 1 + rand( 6 )
on_die_cast( die )
sleep( die )
end
end
# A method to define callback methods.
# When the latter is called with a block, it's saved into a instance variable.
# Else a saved code block is executed.
def callback( *names )
names.each do |name|
eval <<-EOF
##{name} = false
def #{name}( *args, &block )
if( block )
##{name} = block
elsif( ##{name} )
##{name}.call( *args )
end
end
EOF
end
end
end
foo = Foo.new
# What should be done when the callback event is triggered?
foo.on_die_cast do |number|
puts( number )
end
foo.run
I know this is an old post, but others that come across this may find my solution helpful.
http://chrisshepherddev.blogspot.com/2015/02/callbacks-in-pure-ruby-prepend-over.html

Resources