cheap_advice 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "rspec", "~> 2.3.0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.5.2"
12
+ gem "rcov", ">= 0"
13
+ # Scarlet
14
+ gem 'open4'
15
+ gem 'RedCloth'
16
+ gem 'rtex'
17
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Kurt Stephens
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,70 @@
1
+ = cheap_advice
2
+
3
+ Add/remove advice around, before or after methods in Ruby.
4
+
5
+ == Example
6
+
7
+ class MyClass
8
+ def foo
9
+ 42
10
+ end
11
+ end
12
+
13
+ class MyOtherClass
14
+ def bar
15
+ 43
16
+ end
17
+ end
18
+
19
+ a = MyClass.new
20
+ b = MyOtherClass.new
21
+
22
+ trace_advice = CheapAdvice.new(:around) do | ar, body |
23
+ ar.advice[:log].puts "#{Time.now.iso8601(6)} #{ar.rcvr.class} #{ar.method} #{ar.rcvr.object_id}"
24
+ body.call
25
+ ar.advice[:log].puts "#{Time.now.iso8601(6)} #{ar.rcvr.class} #{ar.method} #{ar.rcvr.object_id} => #{ar.result.inspect}"
26
+ end
27
+ trace_advice[:log] = File.open("trace.log", "a+")
28
+ trace_advice.advise!(MyClass, :foo)
29
+ trace_advice.advise!(MyOtherClass, :bar)
30
+
31
+
32
+ a.foo
33
+ b.bar
34
+
35
+ trace_advice.disable!
36
+
37
+ a.foo
38
+ b.bar
39
+
40
+ trace.log will contain something like:
41
+
42
+ 2011-01-17T16:33:27.882122-06:00 MyClass foo 69872883178280
43
+ 2011-01-17T16:33:27.882262-06:00 MyClass foo 69872883178280 => 42
44
+ 2011-01-17T16:33:27.882319-06:00 MyOtherClass bar 69872883178200
45
+ 2011-01-17T16:33:27.882367-06:00 MyOtherClass bar 69872883178200 => 43
46
+
47
+ == Other Features
48
+
49
+ * CheapAdvice::Configuration provides a generic mechanism to configure multiple advices on different methods.
50
+ * CheapAdvice::Trace provides an example advice factory for generic method tracing/logging. See examples/ex02.rb.
51
+
52
+ == Issues
53
+
54
+ * Rails-type autoloading can confuse CheapAdvice.
55
+
56
+ == Contributing to cheap_advice
57
+
58
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
59
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
60
+ * Fork the project
61
+ * Start a feature/bugfix branch
62
+ * Commit and push until you are happy with your contribution
63
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
64
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
65
+
66
+ == Copyright
67
+
68
+ Copyright (c) 2008-2011 Kurt Stephens. See LICENSE.txt for
69
+ further details.
70
+
@@ -0,0 +1,79 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "cheap_advice"
16
+ gem.homepage = "http://github.com/kstephens/cheap_advice"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Add dynamic advice wrappers to methods.}
19
+ gem.description = %Q{http://kurtstephens.com/pub/cheap_advice.slides/index.html}
20
+ gem.email = "ks.github@kurtstephens.com"
21
+ gem.authors = ["Kurt Stephens"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rspec/core'
30
+ require 'rspec/core/rake_task'
31
+ RSpec::Core::RakeTask.new(:spec) do |spec|
32
+ spec.pattern = FileList['spec/**/*_spec.rb']
33
+ end
34
+
35
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
36
+ spec.pattern = 'spec/**/*_spec.rb'
37
+ spec.rcov = true
38
+ end
39
+
40
+ task :example do
41
+ Dir['example/ex*.rb'].sort.each do | ex |
42
+ cpid = Process.fork do
43
+ load ex
44
+ end
45
+ Process.wait(cpid) or raise "#{ex} failed"
46
+ end
47
+ end
48
+
49
+ task :default => :spec
50
+ task :default => :example
51
+
52
+ require 'rake/rdoctask'
53
+ Rake::RDocTask.new do |rdoc|
54
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
55
+
56
+ rdoc.rdoc_dir = 'rdoc'
57
+ rdoc.title = "cheap_advice #{version}"
58
+ rdoc.rdoc_files.include('README*')
59
+ rdoc.rdoc_files.include('lib/**/*.rb')
60
+ end
61
+
62
+ $SCARLET = ENV['SCARLET'] ||= File.expand_path("../../scarlet/bin/scarlet", __FILE__)
63
+
64
+ slides_src = 'cheap_advice.slides.textile'
65
+ slides_html = 'doc/cheap_advice.slides/index.html'
66
+ file slides_html => slides_src do
67
+ slides_dir = File.dirname(slides_html)
68
+ sh "mkdir -p #{slides_dir}"
69
+ sh "#{$SCARLET} -f html -g #{slides_dir}"
70
+ sh "#{$SCARLET} -f html #{slides_src} > #{slides_html}"
71
+ sh "open #{slides_html}"
72
+ end
73
+
74
+ task :doc => slides_html
75
+
76
+ task :publish => :doc do
77
+ sh "rsync -aruzv doc/cheap_advice.slides/ kscom:kurtstephens.com/pub/cheap_advice.slides/"
78
+ end
79
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,257 @@
1
+ !SLIDE
2
+ !TITLE Cheap Advice
3
+
4
+ h1. Cheap Advice
5
+
6
+ * Kurt Stephens
7
+ * Enova Financial -- "http://enovafinancial.com":http://enovafinancial.com
8
+ * RubyConf 2011
9
+ * Slides -- "http://kurtstephens.com/pub/cheap_advice.slides/index.html":http://kurtstephens.com/pub/cheap_advice.slides/index.html
10
+ * Code -- "http://github.com/kstephens/cheap_advice":http://github.com/kstephens/cheap_advice
11
+
12
+ !SLIDE
13
+ !TITLE Clean Code
14
+
15
+ h1. Clean Code
16
+
17
+ @@@ ruby
18
+
19
+ class MyClass
20
+ def foo; 42; end
21
+ end
22
+ class MyOtherClass
23
+ def bar; 43; end
24
+ end
25
+ a = MyClass.new
26
+ b = MyOtherClass.new
27
+ a.foo
28
+ b.bar
29
+
30
+ @@@
31
+
32
+ !SLIDE
33
+ !TITLE Add Logging
34
+
35
+ h1. Add Logging
36
+
37
+ @@@ ruby
38
+
39
+ class MyClass
40
+ def foo
41
+ $stderr.puts "#{self}#foo => 42"
42
+ 42
43
+ end
44
+ end
45
+ class MyOtherClass
46
+ def bar
47
+ $stderr.puts "#{self}#bar => 43"
48
+ 43
49
+ end
50
+ end
51
+ a = MyClass.new
52
+ b = MyOtherClass.new
53
+ a.foo
54
+ b.bar
55
+
56
+ @@@
57
+
58
+ !SLIDE
59
+ !TITLE Add Security
60
+
61
+ h1. Add Security
62
+
63
+ @@@ ruby
64
+
65
+ class MyClass
66
+ def foo
67
+ raise "SecurityError" unless $roles.include?("MyClass#foo")
68
+ $stderr.puts "#{self}#foo => 42"
69
+ 42
70
+ end
71
+ end
72
+ class MyOtherClass
73
+ def bar
74
+ raise "SecurityError" unless $roles.include?("MyClass#bar")
75
+ $stderr.puts "#{self}#bar => 43"
76
+ 43
77
+ end
78
+ end
79
+ a = MyClass.new
80
+ b = MyOtherClass.new
81
+ $roles = [ "MyClass#foo" ]
82
+ a.foo
83
+ b.bar
84
+
85
+ @@@
86
+
87
+ !SLIDE
88
+ !TITLE YUCK!
89
+
90
+ h1. ...YUCK!
91
+
92
+ @@@ ruby
93
+
94
+ class MyClass
95
+ def foo
96
+ # YUCK!: raise "SecurityError" unless $roles.include?("MyClass#foo")
97
+ # YUCK!: $stderr.puts "#{self}#foo => 42"
98
+ 42
99
+ end
100
+ end
101
+ class MyOtherClass
102
+ def bar
103
+ # YUCK!: raise "SecurityError" unless $roles.include?("MyClass#bar")
104
+ # YUCK!: $stderr.puts "#{self}#bar => 43"
105
+ 43
106
+ end
107
+ end
108
+ a = MyClass.new
109
+ b = MyOtherClass.new
110
+ $roles = [ "MyClass#foo" ] # ???
111
+ a.foo
112
+ b.bar
113
+
114
+ @@@
115
+
116
+
117
+ !SLIDE
118
+ !TITLE Dumb and Clean, Smart and Dirty
119
+
120
+ h1. Dumb and Clean, Smart and Dirty
121
+
122
+ * Real World is Smart Code.
123
+ * Dumb Code is Clean, Smart Code is Dirty.
124
+ * Get Dirt Out Of Code -- (problem-domain vs. solution-domain)
125
+ * Sweep It Somewhere Else -- (modularize the smart dirt)
126
+ * Don't be Dirty All the Time -- (dynamic, stateful dirt: logging, debugging, security, etc.)
127
+
128
+ !SLIDE
129
+ !TITLE Separation of Concerns
130
+
131
+ h1. Separation of Concerns
132
+
133
+ * Logging
134
+ * Security
135
+
136
+ ... are not problem-domain issues.
137
+
138
+ !SLIDE
139
+ !TITLE Advice
140
+
141
+ h1. Advice
142
+
143
+ * Commonplace in the Lisp world, (esp. Emacs).
144
+ * Advice is function that wraps another function: "before", "after" or "around".
145
+ * Advice can be added or removed at run-time.
146
+
147
+ !SLIDE
148
+ !TITLE Advice != Aspects
149
+
150
+ h1. Advice != Aspects
151
+
152
+ * Aspects are woven into code based on complex "codepoint" criteria at build-time (or load-time).
153
+ * Advice is applied to a more well-known constructs: applicable objects: functions, methods, etc.
154
+ * Advice are objects.
155
+ * Advice can be added and removed at run-time.
156
+
157
+ !SLIDE
158
+ !TITLE Cheap Advice
159
+
160
+ h1. Cheap Advice
161
+
162
+ * ... adds dynamic Advice to Ruby methods.
163
+ * ... is applied to methods.
164
+ * ... are stateful objects.
165
+ * ... can be added and removed at run-time.
166
+ * ... are configurable.
167
+
168
+ !SLIDE
169
+ !TITLE Logging Advice
170
+
171
+ h1. Logging Advice
172
+
173
+ @@@ ruby
174
+
175
+ # Advice
176
+ trace_advice = CheapAdvice.new(:around) do | ar, body |
177
+ ar.advice[:log] <<
178
+ "#{Time.now.iso8601(6)} " <<
179
+ "#{ar.rcvr.class} #{ar.meth} #{ar.rcvr.object_id}\n"
180
+ body.call
181
+ ar.advice[:log] <<
182
+ "#{Time.now.iso8601(6)} " <<
183
+ "#{ar.rcvr.class} #{ar.meth} #{ar.rcvr.object_id} " <<
184
+ "=> #{ar.result.inspect}\n"
185
+ end
186
+ # State attached to trace_advice.
187
+ trace_advice[:log] = File.open("trace.log", "a+")
188
+
189
+ @@@
190
+
191
+ !SLIDE
192
+ !TITLE Applying Advice
193
+
194
+ h1. Applying Advice
195
+
196
+ @@@ ruby
197
+
198
+ ...
199
+ # Activate trace_advice:
200
+ trace_advice.advise!(MyClass, :foo)
201
+ trace_advice.advise!(MyOtherClass, :bar)
202
+ a.foo
203
+ b.bar
204
+
205
+ # Disable trace_advice:
206
+ trace_advice.disable!
207
+ a.foo
208
+ b.bar
209
+ @@@
210
+
211
+ !SLIDE
212
+ !TITLE Configuration
213
+
214
+ h1. Configuration
215
+
216
+ @@@ yaml
217
+
218
+ :advice:
219
+ ~:
220
+ :enabled: false
221
+ :options:
222
+ :trace:
223
+ :logger:
224
+ :name: :default
225
+
226
+ 'MyClass':
227
+ :advice: trace
228
+
229
+ 'MyClass#foo':
230
+ :enabled: false
231
+
232
+ 'MyClass#bar':
233
+ :enabled: false
234
+
235
+ @@@
236
+
237
+ !SLIDE
238
+ !TITLE Security Advice
239
+
240
+ h1. Security Advice
241
+
242
+ You get the idea.
243
+
244
+ !SLIDE
245
+ !TITLE Example
246
+
247
+ h1. See example/ex01.rb
248
+
249
+ !SLIDE
250
+ !TITLE CheapAdvice
251
+
252
+ h1. Questions?
253
+
254
+ h1. Code!
255
+
256
+ http://github.com/kstephens/cheap_advice
257
+