gcao / aspector Goto Github PK
View Code? Open in Web Editor NEWAspect Oriented Programming (AOP) for Ruby
License: MIT License
Aspect Oriented Programming (AOP) for Ruby
License: MIT License
When attempting to implement something as simple as the around
example, I receive:
wrong number of arguments (2 for 1) (ArgumentError)
/Users/kross/alienfast/cucumber_statistics/lib/cucumber_statistics/autoload.rb:15:in `block (2 levels) in <top (required)>'
/Users/kross/.rvm/gems/ruby-1.9.3-p448@acme/gems/aspector-0.13.1/lib/aspector/base.rb:259:in `block (2 levels) in recreate_method_with_advices'
/Users/kross/.rvm/gems/ruby-1.9.3-p448@acme/gems/aspector-0.13.1/lib/aspector/base.rb:255:in `catch'
/Users/kross/.rvm/gems/ruby-1.9.3-p448@acme/gems/aspector-0.13.1/lib/aspector/base.rb:255:in `block in recreate_method_with_advices'
/Users/kross/.rvm/gems/ruby-1.9.3-p448@acme/gems/cucumber-1.3.10/lib/cucumber/runtime.rb:46:in `run!'
/Users/kross/.rvm/gems/ruby-1.9.3-p448@acme/gems/cucumber-1.3.10/lib/cucumber/cli/main.rb:47:in `execute!'
/Users/kross/.rvm/gems/ruby-1.9.3-p448@acme/gems/cucumber-1.3.10/bin/cucumber:13:in `<top (required)>'
My code:
require 'aspector'
aspector(Cucumber::Cli::Configuration) do
around :build_tree_walker do |proxy, &block|
puts 'before(block)'
proxy.call &block
puts 'after(block)'
end
end
before :test do |input|
set_args input * 100
end
set_args could be renamed to something more interesting
let(:parent_klass) { ClassBuilder.build }
let(:aspect) do
Aspector do
before :exec do
values << 'do_before'
end
end
end
context 'applying to overridden method' do
let(:child_klass) do
ClassBuilder.inherit(parent_klass) do
def exec(_param = nil)
values << 'exec-result-child'
end
end
end
subject { child_klass.new }
it 'should apply a given code to the method' do
aspect.apply(parent_klass)
subject.exec
expect(subject.values).to eq %w( do_before exec-result-child )
end
end
expected: ["do_before", "exec-result"]
got: ["exec-result-child"]
What do you think? Is it valid to expect that applied aspect takes effect on overridden method?
Would be nice to have some examples that show how to access both interception, aspect and interception options
Once we're done with refactoring, we should add code climate to monitor quality of code.
class TestAspect < Aspector::Base
def do_something
puts 'do_something'
end
before :initialize, :do_something
end
TestAspect.apply(SomeClass)
SomeClass.new
#Output:
#do_something
require './lib/aspector'
module Mod
def test
super
end
end
class ARClass
def test
end
end
ARClass.prepend Mod
class Hooks < Aspector::Base
before :test do
end
end
Hooks.apply(ARClass)
ar = ARClass.new
ar.test
aspector/interception.rb:302:in `call'
aspector/interception.rb:302:in `block in recreate_method_with_advices'
from test.rb:5:in `test'
aspector/interception.rb:302:in `call'
aspector/interception.rb:302:in `block in recreate_method_with_advices'
from test.rb:5:in `test'
aspector/interception.rb:302:in `call'
aspector/interception.rb:302:in `block in recreate_method_with_advices'
... 6271 levels...
aspector/interception.rb:302:in `call'
aspector/interception.rb:302:in `block in recreate_method_with_advices'
from test.rb:5:in `test'
from test.rb:25:in `<main>'
after :initialize, "@t = Test.new"
after :test, "@t.do_something"
Facing warnings
gems/aspector-0.14.0/lib/aspector/interception.rb:229: warning: Passing trim_mode with the 3rd argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, trim_mode: ...) instead.
gems/aspector-0.14.0/lib/aspector/interception.rb:229: warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments.
The syntax used for ERB.new in the interception.rb file is deprecated. The issue persists with the latest release 0.14.0 I see in your master this issue is fixed. Please release a new version of Gem with the fix provided.
This gem is great!
Is there a standard way to apply aspects using Mixins?
Normally, when I code I tend to compose objects using traits and I was wondering if this is easily done also with aspector
or if its impossible due to the execution model?
Any thoughts?
Thank you for your time and effort!
Add logging support
Logger levels: error, warn, info, debug, trace
Logger level defaults to info
Logger level can be set through environment variable (e.g. ASPECTOR_LOG_LEVEL=warn+TestAspect/debug)
Logger level can be set programatically
Logger level can be set per Aspect class (or even instance?)
After an aspect is applied, changing logger level has no effect
Warn on using raw advices (warnings can be disabled by setting that aspect's logger level to error)
We can save indexes of advices and simply refer them as "advice 1 (BEFORE)"
Log example
Aspector | INFO | TestAspect | define-advice |
Aspector | DEBUG | TestAspect | before-apply-to | A
Aspector | INFO | TestAspect | apply-to | A
Aspector | DEBUG | TestAspect | after-apply-to | A
Aspector | DEBUG | TestAspect | before-apply-to-method | A |
Aspector | DEBUG | TestAspect | apply-to-method | A | |
Aspector | DEBUG | TestAspect | after-apply-to-method | A |
Aspector | DEBUG | TestAspect | invoke-method | A |
Aspector | DEBUG | TestAspect | invoke-advice | A | |
save reference to prev_aspect and next_aspect in current aspect instance
store method reference before applying aspect
disable/enable aspect by swapping method reference and redefine method if this is the last aspect applicable to method
Default to nil
If set to true, only apply aspects to methods already defined.
Hey, is this gem being maintained? If not I would love to take it over - we use aspector extensively and we would be able to keep it alive.
I feel there is no need to have instance of aspect. Or we can remove Interception and make sure we create an aspect instance for every target.
To be continued...
We should use this: http://ruby-doc.org/core-2.2.2/Module.html instead of ERB templating
This would significantly improve readability - we could describe every option in one place and then use them. We could also provide a validation layer if needed
raw :test do |aspect, method|
# self => target or context where methods are defined?
alias_method method, :"#{method}_orig"
define_method method do |*args, &block|
send :"#{method}_orig"
end
end
Default to true
If set to false, the aspect will be disabled after #apply
Example:
before lambda{target.methods}, :do_this
before proc{target.methods}, :do_this
Reorganization and cleanup without changing any functionalities
This require a 100% code coverage #21
context_arg is a big performance hit.
Method name is enough in many cases.
Provide a default logger but make it possible to be replaced.
logger interface
log levels:
error - 50
warn - 40
info - 30
debug - 20
trace - 10
Hi folks, interesting gem, thanks for sharing. I'm having a hard time understanding how to fully use it tho.
Is there documentation on the domain-specific language keywords?
For example, I've seen default
, target
, etc.
And for available options?
For example, method
, methods
, class_methods
, private_methods
, new_methods_only
, except
, method_arg
, name
, etc.
Thanks! ๐
Probably we should use to_sym since methods definitions are already stored in symbols. Also the GC would have a bit of rest.
Loving this gem. Is there a standard way to remove applied aspects? When I'm testing I want to reset my application to a pure state between tests and I'd like to remove all applied aspects as part of that reset.
Thoughts?
Thanks for your work on this!
aspect can be enabled/disabled. aspect instance can be enabled/disabled independent of the aspect class.
Then aspect instance can be used like a regular class, have instance variable, methods and can be called from advice logic, e.g.
class TestAspect < Aspector::Base
attr_accessor :call_count
def initialize
@call_count = 0
end
before aspect_arg: true do |aspect|
aspect.call_count += 1
end
end
a = TestAspect.new
a.apply A, method: 'do_a'
a.apply B, methods: %w(do_this do_that)
Hey, I was thinking a lot and I think we should mark this library as unmaintained. Why? Because of prepend that allows you to easily build aspects and apply them.
Of course it would require a bit more work to do it, but still - it seems that neither me nor you have the time to maintain the full set of things in this lib (and there are no pull requests going on so no candidates)
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.