saturnflyer / casting Goto Github PK
View Code? Open in Web Editor NEWDelegate methods in Ruby and preserve self. Add behaviors to your objects without altering their superclass hierarchy.
License: MIT License
Delegate methods in Ruby and preserve self. Add behaviors to your objects without altering their superclass hierarchy.
License: MIT License
We recently integrated New Relic into our application to test out some metrics and it initially connects but starts throwing errors to which Casting is a big part of the stack trace.
I wanted to get some thoughts on this to find out if anyone else is using New Relic and whether or not this has been an issue.
RuntimeError: can't modify frozen NewRelic::Agent::Configuration::ServerSource
/var/bundle/ruby/2.2.0/gems/casting-0.7.1/lib/casting/missing_method_client.rb:50:in `__delegates__'
/var/bundle/ruby/2.2.0/gems/casting-0.7.1/lib/casting/missing_method_client.rb:67:in `method_delegate'
/var/bundle/ruby/2.2.0/gems/casting-0.7.1/lib/casting/missing_method_client.rb:63:in `respond_to_missing?'
/var/bundle/ruby/2.2.0/gems/newrelic_rpm-3.16.0.318/lib/new_relic/agent/configuration/manager.rb:99:in `respond_to?'
/var/bundle/ruby/2.2.0/gems/newrelic_rpm-3.16.0.318/lib/new_relic/agent/configuration/manager.rb:99:in `block in source'
/var/bundle/ruby/2.2.0/gems/newrelic_rpm-3.16.0.318/lib/new_relic/agent/configuration/manager.rb:98:in `each'
/var/bundle/ruby/2.2.0/gems/newrelic_rpm-3.16.0.318/lib/new_relic/agent/configuration/manager.rb:98:in `source'
/var/bundle/ruby/2.2.0/gems/newrelic_rpm-3.16.0.318/lib/new_relic/agent/transaction_sample_builder.rb:120:in `transaction_trace_threshold'
/var/bundle/ruby/2.2.0/gems/newrelic_rpm-3.16.0.318/lib/new_relic/agent/transaction_sample_builder.rb:111:in `finish_trace'
/var/bundle/ruby/2.2.0/gems/newrelic_rpm-3.16.0.318/lib/new_relic/agent/transaction_sampler.rb:104:in `on_finishing_transaction'
/var/bundle/ruby/2.2.0/gems/newrelic_rpm-3.16.0.318/lib/new_relic/agent/transaction.rb:519:in `commit!'
/var/bundle/ruby/2.2.0/gems/newrelic_rpm-3.16.0.318/lib/new_relic/agent/transaction.rb:503:in `stop'
/var/bundle/ruby/2.2.0/gems/newrelic_rpm-3.16.0.318/lib/new_relic/agent/transaction.rb:148:in `stop'
/var/bundle/ruby/2.2.0/gems/newrelic_rpm-3.16.0.318/lib/new_relic/agent/instrumentation/middleware_tracing.rb:108:in `call'
/var/bundle/ruby/2.2.0/gems/puma-2.15.3/lib/puma/configuration.rb:79:in `call'
/var/bundle/ruby/2.2.0/gems/puma-2.15.3/lib/puma/server.rb:541:in `handle_request'
/var/bundle/ruby/2.2.0/gems/puma-2.15.3/lib/puma/server.rb:388:in `process_client'
/var/bundle/ruby/2.2.0/gems/puma-2.15.3/lib/puma/server.rb:270:in `block in run'
/var/bundle/ruby/2.2.0/gems/puma-2.15.3/lib/puma/thread_pool.rb:106:in `call'
/var/bundle/ruby/2.2.0/gems/puma-2.15.3/lib/puma/thread_pool.rb:106:in `block in spawn_thread'
The lines in new_relic come down to this
def source(key)
config_stack.each do |config|
if config.respond_to?(key.to_sym) || config.has_key?(key.to_sym)
return config
end
end
end
and on the config.respond_to?
method which seems to get into the fact that it's trying to initialize @delegates on a frozen object.
Tiny detail...
To be consistent with the rest of Ruby's mixins (Enumerable, Comparable, etc.), wouldn't Casting::Client be better named Castable?
Currently, an object will respond to messages from its delegates, but if you ask for a collection of methods
it will not include those from the delegate.
Casting::MissingMethodClient
should report these methods.
# data object
class Request
def scheduled_time_from
'time from'
end
def scheduled_time_to
'time to'
end
end
# presenter
module RequestPresenter
def scheduled_time_from
'formatted' + super
end
def scheduled_time_to
'formatted' + super
end
def scheduled_time_formatted
"#{scheduled_time_from} - #{scheduled_time_to}"
end
end
request = Request.find(1).cast_as(RequestPresenter)
request.scheduled_time_formatted # => 'time to - time from'
scheduled_time_formatted
should return 'formatted time to - formatted time from'.
I hope the issue is clear from the above, I have no idea how to describe it in words.
Is this expected behaviour?
My work around for now is as such:
# presenter
module RequestPresenter
def scheduled_time_from_formatted
'formatted ' + scheduled_time_from
end
def scheduled_time_to_formatted
'formatted ' + scheduled_time_to
end
def scheduled_time_formatted
"#{scheduled_time_from_formatted} - #{scheduled_time_to_formatted}"
end
end
request = Request.find(1).cast_as(RequestPresenter)
request.scheduled_time_formatted # => 'formatted time to - formatted time from'
Currently the standard lib Forwardable and ActiveSupport provide delegate
methods.
Perhaps a fallback to cast
would make sense to prevent confusion.
Currently the super_delegate
added in Casting::Super
will endlessly loop if multiple methods of the same name are used.
There is a high chance I'm just using the library wrong, but here goes:
class User < ActiveRecord::Base
include Casting::Client
end
module Customer; end
user = User.last
user.cast_as(Customer) # => NoMethodError
This is on Ruby 1.9.3.
@saturnflyer can you verify this line in the example is correct?
https://github.com/saturnflyer/casting/blob/master/examples/activation.rb#L26
Seems to be calling back to Activation... Would you mind explaining the reasoning behind that?
What do you think of the idea of adding an optionally required extension for Array and Set to allow this:
[thing_1, thing_2 ... ].cast_members_as(ThingPresenter)
It would return a new array where each member has been cast as a ThingPresenter
.
Out of scope of casting or a consideration?
Currently the Delegation
object requires arguments be given using with
. Allowing arguments with call
would remove surprising behavior.
You might not consider this a casting issue, if so, please close.
If I use a double and somewhere along the way it gets cast_as
it fails because of course the double does not have the Casting::Client
. Do you know of a work around?
# role
class Cancellable
def cancel
end
end
def cancel(order)
order.cast_as(Cancellable)
order.cancel
end
order = double('order')
order.should_receive(:cancel)
cancel(order)
# => Double 'order' received unexpected messgae :cast_as
There is also a concern about recursive class casting. This might be an edge-case, but it seems worthwhile to think about.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.