aspector 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rubocop.yml +26 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +8 -11
  7. data/Changelog.md +59 -0
  8. data/Gemfile +9 -14
  9. data/Gemfile.lock +84 -50
  10. data/README.md +118 -0
  11. data/Rakefile +6 -22
  12. data/aspector.gemspec +15 -127
  13. data/benchmarks/after_benchmark.rb +28 -0
  14. data/benchmarks/around_advice_benchmark.rb +35 -0
  15. data/benchmarks/around_benchmark.rb +32 -0
  16. data/benchmarks/before_benchmark.rb +28 -0
  17. data/benchmarks/benchmark_helper.rb +17 -0
  18. data/benchmarks/combined_benchmark.rb +36 -0
  19. data/benchmarks/method_invocation_benchmark.rb +30 -0
  20. data/benchmarks/raw_benchmark.rb +39 -0
  21. data/examples/activerecord_hooks.rb +10 -15
  22. data/examples/around_example.rb +20 -31
  23. data/examples/aspector_apply_example.rb +10 -17
  24. data/examples/aspector_example.rb +7 -16
  25. data/examples/cache_aspect.rb +20 -30
  26. data/examples/design_by_contract.rb +20 -44
  27. data/examples/exception_handler.rb +12 -20
  28. data/examples/exception_handler2.rb +16 -24
  29. data/examples/implicit_method_option_test.rb +8 -16
  30. data/examples/interception_options_example.rb +71 -0
  31. data/examples/logging_aspect.rb +16 -24
  32. data/examples/process_aspector.rb +13 -0
  33. data/examples/retry_aspect.rb +20 -20
  34. data/lib/aspector.rb +17 -15
  35. data/lib/aspector/advice.rb +44 -57
  36. data/lib/aspector/advice_metadata.rb +10 -11
  37. data/lib/aspector/aspect_instances.rb +2 -3
  38. data/lib/aspector/base.rb +6 -368
  39. data/lib/aspector/base_class_methods.rb +24 -55
  40. data/lib/aspector/deferred_logic.rb +3 -4
  41. data/lib/aspector/deferred_option.rb +5 -10
  42. data/lib/aspector/interception.rb +356 -0
  43. data/lib/aspector/logger.rb +18 -45
  44. data/lib/aspector/logging.rb +10 -29
  45. data/lib/aspector/method_matcher.rb +5 -6
  46. data/lib/aspector/object_extension.rb +4 -12
  47. data/lib/aspector/version.rb +3 -0
  48. data/spec/examples_spec.rb +59 -0
  49. data/spec/functionals/aspect_for_multiple_targets_spec.rb +54 -0
  50. data/spec/functionals/aspect_interception_options_accessing_spec.rb +112 -0
  51. data/spec/functionals/aspect_on_a_class_spec.rb +159 -0
  52. data/spec/functionals/aspect_on_an_instance_spec.rb +66 -0
  53. data/spec/functionals/aspector_spec.rb +138 -0
  54. data/spec/functionals/aspects_combined_spec.rb +37 -0
  55. data/spec/functionals/aspects_execution_order_spec.rb +61 -0
  56. data/spec/functionals/aspects_on_private_methods_spec.rb +82 -0
  57. data/spec/spec_helper.rb +20 -21
  58. data/spec/support/class_builder.rb +44 -0
  59. data/spec/units/advice_spec.rb +49 -0
  60. data/spec/units/advices/after_spec.rb +328 -0
  61. data/spec/units/advices/around_spec.rb +336 -0
  62. data/spec/units/advices/before_filter_spec.rb +287 -0
  63. data/spec/units/advices/before_spec.rb +237 -0
  64. data/spec/units/advices/raw_spec.rb +67 -0
  65. data/spec/units/base_class_methods_spec.rb +262 -0
  66. data/spec/units/base_spec.rb +133 -0
  67. data/spec/units/deferred_logic_spec.rb +35 -0
  68. data/spec/units/logger_spec.rb +20 -0
  69. data/spec/units/logging_spec.rb +85 -0
  70. data/spec/units/method_matcher_spec.rb +95 -0
  71. data/spec/units/object_extension_spec.rb +11 -0
  72. data/spec/units/special_chars_spec.rb +128 -0
  73. metadata +98 -246
  74. data/.document +0 -5
  75. data/.rvmrc +0 -8
  76. data/README.rdoc +0 -80
  77. data/VERSION +0 -1
  78. data/performance-tests/after_test.rb +0 -25
  79. data/performance-tests/around_advice_benchmark.rb +0 -66
  80. data/performance-tests/around_test.rb +0 -27
  81. data/performance-tests/before_test.rb +0 -25
  82. data/performance-tests/combined_test.rb +0 -33
  83. data/performance-tests/method_invocation_test.rb +0 -25
  84. data/performance-tests/raw_test.rb +0 -37
  85. data/performance-tests/test_helper.rb +0 -9
  86. data/run_all_examples.sh +0 -12
  87. data/spec/functional/advices_on_private_methods_spec.rb +0 -21
  88. data/spec/functional/aspect_on_eigen_class_spec.rb +0 -72
  89. data/spec/functional/aspect_on_object_spec.rb +0 -20
  90. data/spec/functional/aspector_spec.rb +0 -140
  91. data/spec/functional/aspects_combined_spec.rb +0 -48
  92. data/spec/functional/execution_order_spec.rb +0 -42
  93. data/spec/unit/advice_spec.rb +0 -4
  94. data/spec/unit/after_spec.rb +0 -88
  95. data/spec/unit/around_spec.rb +0 -76
  96. data/spec/unit/base_class_methods_spec.rb +0 -28
  97. data/spec/unit/base_spec.rb +0 -112
  98. data/spec/unit/before_spec.rb +0 -125
  99. data/spec/unit/deferred_logic_spec.rb +0 -23
  100. data/spec/unit/method_matcher_spec.rb +0 -43
  101. data/spec/unit/raw_spec.rb +0 -53
  102. data/spec/unit/special_chars_spec.rb +0 -122
@@ -1,132 +1,20 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
- # -*- encoding: utf-8 -*-
1
+ require 'aspector/version'
5
2
 
6
3
  Gem::Specification.new do |s|
7
- s.name = %q{aspector}
8
- s.version = "0.13.1"
4
+ s.name = 'aspector'
5
+ s.version = Aspector::VERSION
9
6
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Guoliang Cao"]
12
- s.date = %q{2013-01-23}
13
- s.description = %q{}
14
- s.email = %q{gcao99@gmail.com}
15
- s.extra_rdoc_files = [
16
- "LICENSE.txt",
17
- "README.rdoc"
18
- ]
19
- s.files = [
20
- ".document",
21
- ".irbrc",
22
- ".rspec",
23
- ".rvmrc",
24
- ".travis.yml",
25
- "Gemfile",
26
- "Gemfile.lock",
27
- "Guardfile",
28
- "LICENSE.txt",
29
- "README.rdoc",
30
- "Rakefile",
31
- "VERSION",
32
- "aspector.gemspec",
33
- "examples/activerecord_hooks.rb",
34
- "examples/around_example.rb",
35
- "examples/aspector_apply_example.rb",
36
- "examples/aspector_example.rb",
37
- "examples/cache_aspect.rb",
38
- "examples/design_by_contract.rb",
39
- "examples/exception_handler.rb",
40
- "examples/exception_handler2.rb",
41
- "examples/implicit_method_option_test.rb",
42
- "examples/logging_aspect.rb",
43
- "examples/retry_aspect.rb",
44
- "lib/aspector.rb",
45
- "lib/aspector/advice.rb",
46
- "lib/aspector/advice_metadata.rb",
47
- "lib/aspector/aspect_instances.rb",
48
- "lib/aspector/base.rb",
49
- "lib/aspector/base_class_methods.rb",
50
- "lib/aspector/deferred_logic.rb",
51
- "lib/aspector/deferred_option.rb",
52
- "lib/aspector/logger.rb",
53
- "lib/aspector/logging.rb",
54
- "lib/aspector/method_matcher.rb",
55
- "lib/aspector/module_extension.rb",
56
- "lib/aspector/object_extension.rb",
57
- "performance-tests/after_test.rb",
58
- "performance-tests/around_advice_benchmark.rb",
59
- "performance-tests/around_test.rb",
60
- "performance-tests/before_test.rb",
61
- "performance-tests/combined_test.rb",
62
- "performance-tests/method_invocation_test.rb",
63
- "performance-tests/raw_test.rb",
64
- "performance-tests/test_helper.rb",
65
- "run_all_examples.sh",
66
- "spec/functional/advices_on_private_methods_spec.rb",
67
- "spec/functional/aspect_on_eigen_class_spec.rb",
68
- "spec/functional/aspect_on_object_spec.rb",
69
- "spec/functional/aspector_spec.rb",
70
- "spec/functional/aspects_combined_spec.rb",
71
- "spec/functional/execution_order_spec.rb",
72
- "spec/spec_helper.rb",
73
- "spec/unit/advice_spec.rb",
74
- "spec/unit/after_spec.rb",
75
- "spec/unit/around_spec.rb",
76
- "spec/unit/base_class_methods_spec.rb",
77
- "spec/unit/base_spec.rb",
78
- "spec/unit/before_spec.rb",
79
- "spec/unit/deferred_logic_spec.rb",
80
- "spec/unit/method_matcher_spec.rb",
81
- "spec/unit/raw_spec.rb",
82
- "spec/unit/special_chars_spec.rb"
83
- ]
84
- s.homepage = %q{http://github.com/gcao/aspector}
85
- s.licenses = ["MIT"]
86
- s.require_paths = ["lib"]
87
- s.rubygems_version = %q{1.6.2}
88
- s.summary = %q{Aspect Oriented Ruby Programming}
7
+ s.authors = ['Guoliang Cao', 'Maciej Mensfeld']
8
+ s.date = %w( 2015-07-07 )
9
+ s.email = ['gcao99@gmail.com', 'maciej@mensfeld.pl']
10
+ s.summary = %w( Aspect Oriented Ruby Programming library )
11
+ s.homepage = 'http://github.com/gcao/aspector'
12
+ s.licenses = %w( MIT )
13
+ s.description = %w()
14
+ s.rubygems_version = %w( 1.6.2 )
89
15
 
90
- if s.respond_to? :specification_version then
91
- s.specification_version = 3
92
-
93
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
94
- s.add_development_dependency(%q<rspec>, [">= 0"])
95
- s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
96
- s.add_development_dependency(%q<ruby-prof>, [">= 0"])
97
- s.add_development_dependency(%q<guard>, ["~> 0.8.4"])
98
- s.add_development_dependency(%q<guard-bundler>, ["~> 0.1.3"])
99
- s.add_development_dependency(%q<guard-rspec>, ["~> 0.5.2"])
100
- s.add_development_dependency(%q<guard-shell>, ["~> 0.1.1"])
101
- s.add_development_dependency(%q<rb-fsevent>, [">= 0"])
102
- s.add_development_dependency(%q<growl>, ["~> 1.0.3"])
103
- s.add_development_dependency(%q<awesome_print>, [">= 0"])
104
- s.add_development_dependency(%q<pry>, [">= 0"])
105
- else
106
- s.add_dependency(%q<rspec>, [">= 0"])
107
- s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
108
- s.add_dependency(%q<ruby-prof>, [">= 0"])
109
- s.add_dependency(%q<guard>, ["~> 0.8.4"])
110
- s.add_dependency(%q<guard-bundler>, ["~> 0.1.3"])
111
- s.add_dependency(%q<guard-rspec>, ["~> 0.5.2"])
112
- s.add_dependency(%q<guard-shell>, ["~> 0.1.1"])
113
- s.add_dependency(%q<rb-fsevent>, [">= 0"])
114
- s.add_dependency(%q<growl>, ["~> 1.0.3"])
115
- s.add_dependency(%q<awesome_print>, [">= 0"])
116
- s.add_dependency(%q<pry>, [">= 0"])
117
- end
118
- else
119
- s.add_dependency(%q<rspec>, [">= 0"])
120
- s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
121
- s.add_dependency(%q<ruby-prof>, [">= 0"])
122
- s.add_dependency(%q<guard>, ["~> 0.8.4"])
123
- s.add_dependency(%q<guard-bundler>, ["~> 0.1.3"])
124
- s.add_dependency(%q<guard-rspec>, ["~> 0.5.2"])
125
- s.add_dependency(%q<guard-shell>, ["~> 0.1.1"])
126
- s.add_dependency(%q<rb-fsevent>, [">= 0"])
127
- s.add_dependency(%q<growl>, ["~> 1.0.3"])
128
- s.add_dependency(%q<awesome_print>, [">= 0"])
129
- s.add_dependency(%q<pry>, [">= 0"])
130
- end
16
+ s.files = `git ls-files -z`.split("\x0")
17
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
19
+ s.require_paths = %w( lib )
131
20
  end
132
-
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/benchmark_helper')
2
+
3
+ # Example class that we use with aspector
4
+ class Klass
5
+ aspector do
6
+ after :test, :after_test
7
+ end
8
+
9
+ def test_no_aspect; end
10
+
11
+ def test; end
12
+
13
+ def after_test(_result); end
14
+ end
15
+
16
+ instance = Klass.new
17
+
18
+ RubyProf.start
19
+ ITERATIONS.times { instance.test_no_aspect }
20
+ result = RubyProf.stop
21
+
22
+ print_result(result, 'instance.test_no_aspect')
23
+
24
+ RubyProf.start
25
+ ITERATIONS.times { instance.test }
26
+ result = RubyProf.stop
27
+
28
+ print_result(result, 'instance.test')
@@ -0,0 +1,35 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/benchmark_helper')
2
+
3
+ # Class to which we will bind with aspect
4
+ class Klass
5
+ def test(input)
6
+ input.upcase!
7
+ end
8
+ end
9
+
10
+ # Around aspect for benchmarking
11
+ class AroundAspect < Aspector::Base
12
+ around :test do |proxy, *args, &block|
13
+ begin
14
+ proxy.call(*args, &block)
15
+ rescue
16
+ nil
17
+ end
18
+ end
19
+ end
20
+
21
+ AroundAspect.apply(Klass)
22
+
23
+ instance = Klass.new
24
+
25
+ RubyProf.start
26
+ ITERATIONS.times { instance.test('good') }
27
+ result = RubyProf.stop
28
+
29
+ print_result(result, 'Around advice good')
30
+
31
+ RubyProf.start
32
+ ITERATIONS.times { instance.test(nil) }
33
+ result = RubyProf.stop
34
+
35
+ print_result(result, 'Around advice bad')
@@ -0,0 +1,32 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/benchmark_helper')
2
+
3
+ # Class to which we will bind with aspect
4
+ class Klass
5
+ aspector do
6
+ around :test, :around_test
7
+ end
8
+
9
+ def test_no_aspect; end
10
+
11
+ def test; end
12
+
13
+ def around_test(proxy, &block)
14
+ proxy.call(&block)
15
+ end
16
+ end
17
+
18
+ AroundAspect.apply(Klass)
19
+
20
+ instance = Klass.new
21
+
22
+ RubyProf.start
23
+ ITERATIONS.times { instance.test('good') }
24
+ result = RubyProf.stop
25
+
26
+ print_result(result, 'Around good')
27
+
28
+ RubyProf.start
29
+ ITERATIONS.times { instance.test(nil) }
30
+ result = RubyProf.stop
31
+
32
+ print_result(result, 'Around bad')
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/benchmark_helper')
2
+
3
+ # Class to which we will bind with aspect
4
+ class Klass
5
+ aspector do
6
+ before :test, :before_test
7
+ end
8
+
9
+ def test_no_aspect; end
10
+
11
+ def test; end
12
+
13
+ def before_test; end
14
+ end
15
+
16
+ instance = Klass.new
17
+
18
+ RubyProf.start
19
+ ITERATIONS.times { instance.test_no_aspect }
20
+ result = RubyProf.stop
21
+
22
+ print_result(result, 'instance.test_no_aspect')
23
+
24
+ RubyProf.start
25
+ ITERATIONS.times { instance.test }
26
+ result = RubyProf.stop
27
+
28
+ print_result(result, 'instance.test')
@@ -0,0 +1,17 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+
3
+ require 'rubygems'
4
+ require 'ruby-prof'
5
+ require 'aspector'
6
+
7
+ # Will print results in the way we want
8
+ def print_result(result, description)
9
+ printer = RubyProf::FlatPrinter.new(result)
10
+ print "#{'-' * 50} #{description}\n"
11
+ printer.print(STDOUT)
12
+ end
13
+
14
+ ITERATIONS = 20_000
15
+ # We disable GC so it won't mess with our benchmarking
16
+ # Don't do this in production
17
+ GC.disable
@@ -0,0 +1,36 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/benchmark_helper')
2
+
3
+ # Class to which we will bind with aspect
4
+ class Klass
5
+ aspector do
6
+ before :test, :before_test
7
+ after :test, :after_test
8
+ around :test, :around_test
9
+ end
10
+
11
+ def test_no_aspect; end
12
+
13
+ def test; end
14
+
15
+ def before_test; end
16
+
17
+ def after_test(_result); end
18
+
19
+ def around_test(proxy, &block)
20
+ proxy.call(&block)
21
+ end
22
+ end
23
+
24
+ instance = Klass.new
25
+
26
+ RubyProf.start
27
+ ITERATIONS.times { instance.test_no_aspect }
28
+ result = RubyProf.stop
29
+
30
+ print_result(result, 'instance.test_no_aspect')
31
+
32
+ RubyProf.start
33
+ ITERATIONS.times { instance.test }
34
+ result = RubyProf.stop
35
+
36
+ print_result(result, 'instance.test')
@@ -0,0 +1,30 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/benchmark_helper')
2
+
3
+ # Class with method invokation
4
+ class Klass
5
+ def do_something; end
6
+
7
+ def test
8
+ do_something
9
+ end
10
+
11
+ do_something_method = instance_method(:do_something)
12
+
13
+ define_method :test_with_method_object do
14
+ do_something_method.bind(self).call
15
+ end
16
+ end
17
+
18
+ instance = Klass.new
19
+
20
+ RubyProf.start
21
+ ITERATIONS.times { instance.test }
22
+ result = RubyProf.stop
23
+
24
+ print_result(result, 'instance.test')
25
+
26
+ RubyProf.start
27
+ ITERATIONS.times { instance.test_with_method_object }
28
+ result = RubyProf.stop
29
+
30
+ print_result(result, 'instance.test_with_method_object')
@@ -0,0 +1,39 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/benchmark_helper')
2
+
3
+ # Class to which we will bind with aspect
4
+ class Klass
5
+ aspector do
6
+ raw :test do |method, _aspect|
7
+ # rubocop:disable Eval
8
+ eval <<-CODE
9
+ alias #{method}_without_aspect #{method}
10
+
11
+ define_method :#{method} do
12
+ return #{method}_without_aspect if aspect.disabled?
13
+ before_#{method}
14
+ #{method}_without_aspect
15
+ end
16
+ CODE
17
+ end
18
+ end
19
+
20
+ def test_no_aspect; end
21
+
22
+ def test; end
23
+
24
+ def before_test; end
25
+ end
26
+
27
+ instance = Klass.new
28
+
29
+ RubyProf.start
30
+ ITERATIONS.times { instance.test_no_aspect }
31
+ result = RubyProf.stop
32
+
33
+ print_result(result, 'instance.test_no_aspect')
34
+
35
+ RubyProf.start
36
+ ITERATIONS.times { instance.test }
37
+ result = RubyProf.stop
38
+
39
+ print_result(result, 'instance.test')
@@ -1,4 +1,8 @@
1
- class A
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require 'aspector'
3
+
4
+ # Class that fakes the ActiveRecord class
5
+ class ARClass
2
6
  def initialize
3
7
  end
4
8
 
@@ -6,16 +10,9 @@ class A
6
10
  end
7
11
  end
8
12
 
9
- ##############################
10
-
11
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
12
-
13
- require 'aspector'
14
-
13
+ # Our ActiveRecord hooks aspect
15
14
  class ActiveRecordHooks < Aspector::Base
16
- logger.level = Aspector::Logging::TRACE
17
-
18
- default :private_methods => true
15
+ default private_methods: true
19
16
 
20
17
  before :initialize do
21
18
  puts "Before creating #{self.class.name} instance"
@@ -26,9 +23,7 @@ class ActiveRecordHooks < Aspector::Base
26
23
  end
27
24
  end
28
25
 
29
- ##############################
30
-
31
- ActiveRecordHooks.apply(A)
26
+ ActiveRecordHooks.apply(ARClass)
32
27
 
33
- a = A.new
34
- a.save
28
+ ar = ARClass.new
29
+ ar.save
@@ -1,44 +1,33 @@
1
- class A
2
- def test
3
- puts 'test 1'
4
- yield
5
- puts 'test 2'
6
- end
7
- end
8
-
9
- ##############################
10
-
11
1
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
12
-
13
2
  require 'aspector'
14
3
 
15
- aspector(A) do
4
+ # Example class to which we will apply our aspects
5
+ class ExampleClass
6
+ def test(arg)
7
+ puts "test(#{arg}) 1"
8
+ yield arg
9
+ puts "test(#{arg}) 2"
10
+ end
11
+ end
12
+
13
+ aspector(ExampleClass) do
16
14
  target do
17
- def do_this proxy, &block
18
- puts 'before'
19
- proxy.call &block
20
- puts 'after'
15
+ def do_this(proxy, arg, &block)
16
+ puts "do_this(#{arg}) 1"
17
+ proxy.call arg, &block
18
+ puts "do_this(#{arg}) 2"
21
19
  end
22
20
  end
23
21
 
24
22
  around :test, :do_this
25
23
 
26
- around :test do |proxy, &block|
27
- puts 'before(block)'
28
- proxy.call &block
29
- puts 'after(block)'
24
+ around :test, name: 'advice2' do |proxy, arg, &block|
25
+ puts "advice2(#{arg}) 1"
26
+ proxy.call arg, &block
27
+ puts "advice2(#{arg}) 2"
30
28
  end
31
29
  end
32
30
 
33
- ##############################
34
-
35
- A.new.test do
36
- puts 'in block'
31
+ ExampleClass.new.test 'x' do |arg|
32
+ puts "block(#{arg})"
37
33
  end
38
-
39
- # Expected output:
40
- # before
41
- # before(block)
42
- # test
43
- # after(block)
44
- # after