aspekt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []