aspekt 0.0.1

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 (4) hide show
  1. data/Gemfile +3 -0
  2. data/README.rdoc +19 -0
  3. data/lib/aspekt.rb +137 -0
  4. metadata +80 -0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'is_same'
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = IN THE MAKING, NOT USABLE
2
+
3
+ == Installation
4
+
5
+ Add to your Gemfile:
6
+ gem 'aspekt'
7
+
8
+ And run:
9
+ bundle install
10
+
11
+ Or run:
12
+ gem install aspekt
13
+
14
+
15
+ == Usage examples
16
+
17
+ === Including before, after and around methods support into Object or Class
18
+
19
+ === Creating aspects
data/lib/aspekt.rb ADDED
@@ -0,0 +1,137 @@
1
+ require 'is_same' # https://github.com/tione/is_same
2
+
3
+
4
+ # Supports only already existing objects (and classes) and methods Weaving.
5
+ # Aspects defined in folder ./aspects will add runtime loading.
6
+ #
7
+ # @see Aspekt::Pointcut
8
+ # @see Aspekt::Advice
9
+ module Aspekt
10
+
11
+
12
+
13
+ # All Aspekt's objects are extended from Aspekt::Object.
14
+ class Object < Hash
15
+
16
+ # Creates a new Aspekt::Object with base class Hash and registres self in class :@all.
17
+ def initialize opts
18
+ self.merge! opts
19
+ self.class.all << self
20
+ end
21
+
22
+ # Returns all Objects created.
23
+ def self.all
24
+ @all ||= []
25
+ end
26
+
27
+ end
28
+
29
+
30
+ class Pointcut < Aspekt::Object
31
+
32
+ # === Example usage
33
+ # class SomeClass
34
+ #
35
+ # def self.some_method
36
+ # return "some_value_from_singleton"
37
+ # end
38
+ #
39
+ # def some_method
40
+ # return "some_value"
41
+ # end
42
+ #
43
+ # def other_method
44
+ # return "other_value"
45
+ # end
46
+ #
47
+ # end
48
+ #
49
+ # some_object = SomeClass.new
50
+ #
51
+ # ==== Pointcuts for instance with types
52
+ # pointcut = Aspekt::Pointcut.new( class: :SomeClass, method: :some_method )
53
+ # pointcut = Aspekt::Pointcut.new( class: SomeClass, method: /some/ )
54
+ # pointcut = Aspekt::Pointcut.new( class: /Some/, method: /some/ )
55
+ #
56
+ # ==== Pointcut for class method (singleton method)
57
+ # pointcut = Aspekt::Pointcut.new( object: SomeClass, method: :some_method )
58
+ # pointcut = Aspekt::Pointcut.new( object: /Some/, method: /some/)
59
+ # pointcut = Aspekt::Pointcut.new( class: (class SomeClass; class<<self; self; end; end, method: :some_method )
60
+ #
61
+ # ==== Pointcut for only one object
62
+ # pointcut = Aspekt::Pointcut.new( object: some_object, method: :some_method)
63
+ #
64
+ # === Arguments
65
+ # - object: object, method: :method
66
+ # - [{object: object, method: :method}, {object: object2, method: :method2
67
+ # - objects: [object, object2], methods: [:method, :method2]
68
+ # - class: :SomeClass, methods: [:method, :method2]
69
+ # - [{objects: [Hash, Array], method: new}, {class: Array, method: :push}, {classes: [Hash, Array, SomeClass], method: /_id/}]
70
+ #
71
+ # ==== Limitations
72
+ # Instances of Regexp, Symbol and Constant are used as finders not thought of as objects.
73
+ # TODO: Fix. Possibly add a new hash key value?
74
+
75
+ def initialize *matchers
76
+ matchers = matchers.flatten.each do |matcher|
77
+ matcher[:classes] = [matcher.delete(:class)].flatten if matcher.has_key?(:class)
78
+ matcher[:objects] = [matcher.delete(:object)].flatten if matcher.has_key?(:object)
79
+ matcher[:methods] = [matcher.delete(:method)].flatten if matcher.has_key?(:method)
80
+ end
81
+ super matchers: matchers
82
+ end
83
+
84
+ # === Example usage
85
+ # pointcut = Aspekt::Pointcut.new( class: :SomeClass, method: :some_method ).is_matching?( object: SomeClass.new )
86
+ # pointcut = Aspekt::Pointcut.new( object: :SomeClass, method: :some_method ).is_matching?( object: SomeClass )
87
+ #
88
+ # === Arguments
89
+ # - object: object
90
+ # - object: object, method: :method
91
+ def is_matching? opts
92
+ raise ArgumentError, "has to include keys 'object', may include 'method'." unless opts[:object]
93
+
94
+ self[:matchers].each do |matcher|
95
+ # object matching
96
+ return true if
97
+ (matcher.has_key(:objects) and matcher[:objects].select{|object| object.is_same?(opts[:object])}.length > 0) or
98
+ (matcher.has_key(:classes) and matcher[:classes].select{|klass| klass.is_same?(opts[:object].class.name)}.length > 0)
99
+ # method matching
100
+ return true unless opts.has_key?(:methods) or
101
+ (matcher.has_key(:methods) and matcher[:methods].select{|klass| klass.is_same?(opts[:methods].class.name)}.length > 0)
102
+ end
103
+
104
+ return false
105
+ end
106
+
107
+ end
108
+
109
+
110
+
111
+ class Advice < Aspekt::Object
112
+
113
+ # == Example usage
114
+ # advice = Aspekt::Advice.new ( type: :before, pointcut: pointcut ) do |joinpoint|
115
+ # puts "before #{joinpoint}"
116
+ # end
117
+ #
118
+ # advice = Aspekt::Advice.new ( type: :around, pointcuts: [pointcut1, pointcut2]) do |joinpoint|
119
+ # puts "around :start for #{joinpoint}"
120
+ # return_value = joinpoint.proceed
121
+ # puts "around :end for #{joinpoint}"
122
+ # end
123
+ #
124
+ def initialize opts
125
+ opts[:pointcuts] = [opts.delete(:pointcut)].flatten if opts[:pointcut]
126
+ super opts
127
+ raise ArgumentError, "type has to be Symbol: before, after or around" unless [:before, :after, :around].include?(self[:type])
128
+ raise ArgumentError, "no pointcut defined" unless self[:pointcuts].length
129
+ end
130
+
131
+ end
132
+
133
+
134
+
135
+ end
136
+
137
+
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aspekt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Margus Pärt
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-13 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: is_same
16
+ requirement: &22453880 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *22453880
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &22453420 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *22453420
36
+ - !ruby/object:Gem::Dependency
37
+ name: rdoc
38
+ requirement: &22453000 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *22453000
47
+ description: Before, after and around method calls. Supports Regexp matching.
48
+ email: margus@tione.eu
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - README.rdoc
54
+ - Gemfile
55
+ - lib/aspekt.rb
56
+ homepage: https://github.com/tione/aspekt
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: 1.9.2
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 1.8.15
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: IN THE MAKING, NOT USABLE.
80
+ test_files: []