I read that attr_writer :age is short hand for this:
def age=(value)
#age = value
end
So I created a class with a function like this:
def age=(value)
if #age == -1
#age = value
return true
end
return false
end
Then I wanted to call it like this in another place:
rv = Foo.age(1)
# do stuff with rv
But I get an error:
ArgumentError:
wrong number of arguments (given 1, expected 0)
Anyway, I can do something like Foo.age = 1 but that doesn't give me control over the return value. What is the proper idiomatic Ruby here?
how about a wrapper method that do 2 steps: first it'll try to set value age= then validate that age == new_value and return, so that you could know that the setter is success or not.
class Foo
def age=(val)
# do a bunch of complicated networking that was non-deterministic
# return true/false
end
def set_age(val)
self.age = val
#age == val
end
end
foo = Foo.new
result = foo.set_age(1)
you could also replace true/false by raising an error, then you could wrap setter into a begin-end block
class Foo
def age=(val)
# do a bunch of complicated networking that was non-deterministic
raise RuntimeError
end
end
result = begin
foo.age = 1
true
rescue => e
false
end
Related
Given a set of class definitions:
class Application
def self.open_current
return Current.new()
end
end
class Current
def get_row(row)
Row.new(row)
end
end
class Row
def get_col(row)
#...
end
end
Design a Proxy class which will:
Create Proxy<<Class>> versions of each class which are extendable via
class ProxyApplication
def myMethod()
#...
end
end
#...
Wrap all return values of all methods in each class such that a proxied class is always used instead of a standard class. I.E.
app = Proxy.new(Application) #app == ProxyApplication
current = app.open_current #current == #<ProxyCurrent>
Ultimately, the definition of Proxy must be dynamic rather than static definitions.
I've been working on this problem for about 6 hours now. I've got the following code. This includes 3 sections:
Initial class setup
Proxy class definition
Testing proxy class
Currently I've got to the point where pApplication=Proxy.new(Application) returns #<Proxy> and pApplication.open_current returns #<ProxyCurrent> which seems kind of on the correct line. However currently it errors when delegate.rb tries to call test() with 2,3 arguments instead of 0...
But my question is, realistically am I going about this correctly? Is using SimpleDelegator the easiest way to do this? One current problem is I'm basically having to add new functionality to the existing SimpleDelegator. I've also looked at using Forwardable, but having to delegate methods manually is not where I want to go with this project, if possible.
Any ideas?
Due to numerous limitations with the initial idea of packing all the calls into a single class, I redesigned it a bit, but it works in exactly the same way.
def proxy__enwrap(obj)
isClass = obj.is_a?(Class)
oldClass = isClass ? obj : obj.class
sNewClass = "Proxy#{oldClass.to_s}"
code = <<-EOF
class #{sNewClass}
include InstanceProxy
def self.__cinit__(obj)
##__cobj__ = obj
end
def self.__cget__
##__cobj__
end
def self.method_missing(m,*args,&block)
if ##__cobj__.respond_to? m
retVal = ##__cobj__.public_send(m,*args,*block)
return proxy__enwrap(retVal)
else
puts "ERROR " + m.to_s + "(" + args.to_s + ") + block?"
#Throw error
end
end
end
#{sNewClass}.__cinit__(#{oldClass.to_s})
if isClass
return #{sNewClass}
else
return #{sNewClass}.new(obj)
end
EOF
::Kernel.eval(code)
end
module InstanceProxy
def method_missing(m,*args,&block)
retVal = #__obj__.__send__(m,*args,&block)
return proxy__enwrap(retVal)
end
def initialize(obj)
#__obj__ = obj
end
end
XXApplication = Application
::Object.const_set "Application", proxy__enwrap(Application)
Currently the only issue is that the object doesn't wrap correctly around yielded objects... I'm not sure if that's even possible though.
Edit:
I've improved the system to also wrap objects passed in as blocks:
def proxy__enwrap(obj)
isClass = obj.is_a?(Class)
oldClass = isClass ? obj : obj.class
sNewClass = "Proxy#{oldClass.to_s}"
code = <<-EOF
class #{sNewClass}
include InstanceProxy
def self.__cinit__(obj)
##__cobj__ = obj
end
def self.__cget__
##__cobj__
end
def self.to_ary
#fix for puts (puts calls to_ary. see: https://stackoverflow.com/questions/8960685/ruby-why-does-puts-call-to-ary)
[self.to_s]
end
def self.method_missing(m,*args,&block)
#Wrap block arguments:
newBlock = Proc.new {}
if block_given?
newBlock = Proc.new do |*args|
args = args.map {|arg| proxy__enwrap(arg)}
block.call(*args)
end
end
#Call delegated functions. Raise error if object doesn't respond to method.
#Return wrapped value
if ##__cobj__.respond_to? m
retVal = ##__cobj__.public_send(m,*args,*block)
return proxy__enwrap(retVal)
else
raise ArgumentError.new("Method '\#\{m.to_s}' doesn't exist.")
end
end
end
#{sNewClass}.__cinit__(#{oldClass.to_s})
if isClass
return #{sNewClass}
else
return #{sNewClass}.new(obj)
end
EOF
::Kernel.eval(code)
end
module InstanceProxy
def method_missing(m,*args,&block)
#Wrap block arguments:
newBlock = Proc.new {}
if block_given?
newBlock = Proc.new do |*args|
args = args.map {|arg| proxy__enwrap(arg)}
block.call(*args)
end
end
#Call delegated functions. Raise error if object doesn't respond to method.
#Return wrapped value
if #__obj__.respond_to? m
retVal = #__obj__.__send__(m,*args,&newBlock)
return proxy__enwrap(retVal)
else
raise ArgumentError.new("Method '#{m.to_s}' doesn't exist.")
end
end
def initialize(obj)
#__obj__ = obj
end
def to_ary
#fix for puts (puts calls to_ary. see: https://stackoverflow.com/questions/8960685/ruby-why-does-puts-call-to-ary)
[self.to_s]
end
end
#
XXApplication = Application
#Silence warnings of overwriting constant
original_verbosity = $VERBOSE
$VERBOSE = nil
::Object.const_set "Application", proxy__enwrap(Application)
$VERBOSE = original_verbosity
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)
Is there any way to "turn on" the strict arity enforcement of a Proc instantiated using Proc.new or Kernel.proc, so that it behaves like a Proc instantiated with lambda?
My initialize method takes a block &action and assigns it to an instance variable. I want action to strictly enforce arity, so when I apply arguments to it later on, it raises an ArgumentError that I can rescue and raise a more meaningful exception. Basically:
class Command
attr_reader :name, :action
def initialize(name, &action)
#name = name
#action = action
end
def perform(*args)
begin
action.call(*args)
rescue ArgumentError
raise(WrongArity.new(args.size))
end
end
end
class WrongArity < StandardError; end
Unfortunately, action does not enforce arity by default:
c = Command.new('second_argument') { |_, y| y }
c.perform(1) # => nil
action.to_proc doesn't work, nor does lambda(&action).
Any other ideas? Or better approaches to the problem?
Thanks!
Your #action will be a Proc instance and Procs have an arity method so you can check how many arguments the block is supposed to have:
def perform(*args)
if args.size != #action.arity
raise WrongArity.new(args.size)
end
#action.call(*args)
end
That should take care of splatless blocks like { |a| ... } and { |a,b| ... } but things are a little more complicated with splats. If you have a block like { |*a| ... } then #action.arity will be -1 and { |a,*b| ... } will give you an arity of -2. A block with arity -1 can take any number of arguments (including none), a block with arity -2 needs at least one argument but can take more than that, and so on. A simple modification of splatless test should take care of the splatful blocks:
def perform(*args)
if #action.arity >= 0 && args.size != #action.arity
raise WrongArity.new(args.size)
elsif #action.arity < 0 && args.size < -(#action.arity + 1)
raise WrongArity.new(args.size)
end
#action.call(*args)
end
According to this answer, the only way to convert a proc to a lambda is using define_method and friends. From the docs:
define_method always defines a method without the tricks [i.e. a lambda-style Proc], even if a non-lambda Proc object is given. This is the only exception for which the tricks are not preserved.
Specifically, as well as actually defining a method, define_method(:method_name, &block) returns a lambda. In order to use this without defining a bunch of methods on some poor object unnecessarily, you could use define_singleton_method on a temporary object.
So you could do something like this:
def initialize(name, &action)
#name = name
#action = to_lambda(&action)
end
def perform(*args)
action.call(*args)
# Could rescue ArgumentError and re-raise a WrongArity, but why bother?
# The default is "ArgumentError: wrong number of arguments (0 for 1)",
# doesn't that say it all?
end
private
def to_lambda(&proc)
Object.new.define_singleton_method(:_, &proc)
end
Your solution:
class Command
attr_reader :name, :action
def initialize(name) # The block argument is removed
#name = name
#action = lambda # We replace `action` with just `lambda`
end
def perform(*args)
begin
action.call(*args)
rescue ArgumentError
raise(WrongArity.new(args.size))
end
end
end
class WrongArity < StandardError; end
Some references:
"If Proc.new is called from inside a method without any arguments of its own, it will return a new Proc containing the block given to its surrounding method."
-- http://mudge.name/2011/01/26/passing-blocks-in-ruby-without-block.html
It turns out that lambda works in the same manner.
How can I limit a variable that belongs to new Class < Fixnum, between 0 and 255?
Or if I can't create a limit in subclass of Fixnim how to write my own class with limit?
Don't make the number a class, make access to that number limited as part of your class via a setter method.
Within your class never set the instance variable except via the setter method.
If you need to do this often, make a helper method for it:
class Module
def limited_value( name, range=0..100 )
attr_reader name
define_method(:"#{name}=") do |new_value|
if range.include?( new_value )
instance_variable_set :"##{name}", new_value
else
raise "Out of Bounds"
end
end
end
end
class Foo
limited_value :bar, 0..255
end
f = Foo.new
p f.bar #=> nil
f.bar = 10
p f.bar #=> 10
f.bar = 300
#=> tmp.rb:8:in `block in limited_value': Out of Bounds (RuntimeError)
You could alternatively choose to set the value to the nearest limit instead of raising a runtime error.
Write a non inherited class and use method_missing to call all functions from a instance variable, them, limit the return value.
class MyNum
instance_methods.each {|m| eval("undef " << m) }
def initialize(fixnum)
#num = fixnum
end
def method_missing(name, *args, &blk)
ret = #num.__send__(name, *args, &blk)
Numeric === ret ? MyNum.new([[ret, 0].max, 255].min) : ret
rescue NoMethodError
super
end
def inspect
"MyNum(#{#num.inspect})"
end
def class
MyNum
end
end
int = MyNum.new(50) # => MyNum(50)
int += 52 # => MyNum(102)
int.succ # => MyNum(103)
int + 300 # => MyNum(255)
int = -int # => MyNum(0)
int.zero? # => true
int == 0 # => true
I'm trying to understand this function.
What I can see is an attribute and type are passed to the opal() method.
Then type_name takes its value from type as long as type is a Symbol or String. Otherwise, the name method is called on type. I imagine the name method is similar to the class method to get the class of the type argument.
After self.class_eval I'm kind of lost but my guess is this is defining maybe a block of code to be added to the class referenced by self.
How this works I'm not sure though.
Would appreciate if someone could explain what's going on after self.class_eval << DEF.
def opal(attr, type)
self.ds "#{attr}_id"
type_name = (type.is_a?(Symbol) || type.is_a?(String)) ? type : type.name
self.class_eval <<DEF
def #{attr}
if defined?(##{attr})
##{attr}
else
##{attr} = if self.#{attr}_id
#{type_name}.get(self.#{attr}_id)
else
nil
end
end
end
def #{attr}=(value)
self.#{attr}_id = value.key
##{attr} = value
end
DEF
end
Everything between <<DEF and DEF is just a string and the #{ ... }s work on that string like any other.
class_eval will cause the interpreter to run on the string in the context of the module.
So, if you know what attr and type are then you can work out what code is being run to add methods to the class.
Lets say attr is "foo" and type is "Bazzle". The code being run would be:
def foo
if defined?(#foo)
#foo
else
#foo = if self.foo_id
Bazzle.get(self.foo_id)
else
nil
end
end
end
def foo=(value)
self.foo_id = value.key
#foo = value
end
To make it easy to understand, let's suppose the value of 'attr' is 'foo', here's what it looks like now:
self.class_eval <<DEF
def foo
if defined?(#foo) # Return the value of attr if it's defined
#foo
else
#foo = if self.foo_id
#{type_name}.get(self.foo_id)
else
nil
end
end
end
def foo=(value) # Define setter
self.foo_id = value.key
#foo = value
end
DEF
So it's just defining some getter and setter methods for #foo, and evaluating it at the class level.