hero 0.0.7 → 0.0.8
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.
- data/README.md +20 -14
- data/lib/hero/observer.rb +11 -6
- data/spec/formula_spec.rb +18 -4
- metadata +2 -2
data/README.md
CHANGED
@@ -36,7 +36,7 @@ you have a lump of spaghetti that's difficult to maintain and even harder to imp
|
|
36
36
|
|
37
37
|
Hero provides a simple pattern that encourages you to
|
38
38
|
<a href="http://en.wikipedia.org/wiki/Decomposition_(computer_science)">decompose</a>
|
39
|
-
these processes into managable chunks.
|
39
|
+
these processes into managable chunks.
|
40
40
|
|
41
41
|
---
|
42
42
|
|
@@ -48,6 +48,8 @@ gem install hero
|
|
48
48
|
|
49
49
|
Lets model a business process for collecting the top news stories from Hacker News, Reddit, & Google and then emailing the results to someone.
|
50
50
|
|
51
|
+
---
|
52
|
+
|
51
53
|
Gather News
|
52
54
|
|
53
55
|
- Get news from Hacker News
|
@@ -55,28 +57,30 @@ Gather News
|
|
55
57
|
- Get news from Google
|
56
58
|
- Email Results
|
57
59
|
|
60
|
+
---
|
61
|
+
|
58
62
|
Now that we have the basic requirements, lets model it with Hero.
|
59
63
|
|
60
64
|
```ruby
|
61
|
-
Hero::Formula[:gather_news].add_step :hacker_news do |context|
|
65
|
+
Hero::Formula[:gather_news].add_step :hacker_news do |context, options|
|
62
66
|
# make api call
|
63
67
|
# parse results
|
64
68
|
# append results to context
|
65
69
|
end
|
66
70
|
|
67
|
-
Hero::Formula[:gather_news].add_step :reddit do |context|
|
71
|
+
Hero::Formula[:gather_news].add_step :reddit do |context, options|
|
68
72
|
# make api call
|
69
73
|
# parse results
|
70
74
|
# append results to context
|
71
75
|
end
|
72
76
|
|
73
|
-
Hero::Formula[:gather_news].add_step :google do |context|
|
77
|
+
Hero::Formula[:gather_news].add_step :google do |context, options|
|
74
78
|
# make api call
|
75
79
|
# parse results
|
76
80
|
# append results to context
|
77
81
|
end
|
78
82
|
|
79
|
-
Hero::Formula[:gather_news].add_step :email do |context|
|
83
|
+
Hero::Formula[:gather_news].add_step :email do |context, options|
|
80
84
|
# format news for email
|
81
85
|
# compose the email
|
82
86
|
# send the email
|
@@ -108,14 +112,16 @@ And we're done.
|
|
108
112
|
|
109
113
|
### Key take aways
|
110
114
|
|
111
|
-
-
|
112
|
-
*
|
115
|
+
- The implementation aligns perfectly with the requirements.
|
116
|
+
*Developers and business folks can talk the same lingo.*
|
117
|
+
|
118
|
+
- The formula is composed of smaller steps that are interchangable.
|
119
|
+
*We are poised for changing requirements.*
|
120
|
+
|
121
|
+
- Steps can be tested independently.
|
113
122
|
|
114
|
-
-
|
115
|
-
*This means we are poised for changing requirements.*
|
123
|
+
- Each step implements the interface: `def call(context, options)`
|
116
124
|
|
117
|
-
- **Each step implements the interface `def call(context)`**
|
118
|
-
*This means we can create step classes to simplify the app structure.*
|
119
125
|
|
120
126
|
## Next Steps
|
121
127
|
|
@@ -124,7 +130,7 @@ Here's an example.
|
|
124
130
|
|
125
131
|
```ruby
|
126
132
|
# this
|
127
|
-
Hero::Formula[:gather_news].add_step :hacker_news do |context|
|
133
|
+
Hero::Formula[:gather_news].add_step :hacker_news do |context, options|
|
128
134
|
# make api call
|
129
135
|
# parse results
|
130
136
|
# append results to context
|
@@ -134,7 +140,7 @@ end
|
|
134
140
|
module GatherNews
|
135
141
|
class HackerNews
|
136
142
|
|
137
|
-
def call(context)
|
143
|
+
def call(context, options)
|
138
144
|
# make api call
|
139
145
|
# parse results
|
140
146
|
# append results to context
|
@@ -169,7 +175,7 @@ Hero::Formula[:gather_news].add_step :google, GatherNews::Google.new
|
|
169
175
|
Hero::Formula[:gather_news].add_step :email, GatherNews::Email.new
|
170
176
|
```
|
171
177
|
|
172
|
-
Now we have a well structured application
|
178
|
+
Now we have a well structured application thats ready to grow.
|
173
179
|
Notice how well organized everything is.
|
174
180
|
|
175
181
|
Also note that we can write tests for each step independent of anything else.
|
data/lib/hero/observer.rb
CHANGED
@@ -59,13 +59,18 @@ module Hero
|
|
59
59
|
# @param optional [Hash] options An option Hash to be passed to each step.
|
60
60
|
def update(context=nil, options={})
|
61
61
|
steps.each do |step|
|
62
|
-
log_step(:before, step, context, options)
|
63
|
-
|
64
|
-
|
62
|
+
log_step(:info, :before, step, context, options)
|
63
|
+
begin
|
64
|
+
step.last.call(context, options)
|
65
|
+
rescue Exception => ex
|
66
|
+
log_step(:error, :after, step, context, options)
|
67
|
+
raise ex
|
68
|
+
end
|
69
|
+
log_step(:info, :after, step, context, options)
|
65
70
|
end
|
66
71
|
end
|
67
72
|
|
68
|
-
private
|
73
|
+
private
|
69
74
|
|
70
75
|
# Logs a step to the registered Hero.logger.
|
71
76
|
# @note Users info for the log level.
|
@@ -73,9 +78,9 @@ module Hero
|
|
73
78
|
# @param [Object] step
|
74
79
|
# @param [Object] context
|
75
80
|
# @param [Object] options
|
76
|
-
def log_step(id, step, context, options)
|
81
|
+
def log_step(level, id, step, context, options)
|
77
82
|
return unless Hero.logger
|
78
|
-
Hero.logger.
|
83
|
+
Hero.logger.send level, "HERO #{id.to_s.ljust(6)} #{formula_name} -> #{step.first} Context: #{context.inspect} Options: #{options.inspect}"
|
79
84
|
end
|
80
85
|
|
81
86
|
end
|
data/spec/formula_spec.rb
CHANGED
@@ -118,10 +118,9 @@ describe Hero::Formula do
|
|
118
118
|
it "should support logging" do
|
119
119
|
class TestLogger
|
120
120
|
attr_reader :buffer
|
121
|
-
def
|
122
|
-
|
123
|
-
|
124
|
-
end
|
121
|
+
def initialize; @buffer = []; end
|
122
|
+
def info(value); @buffer << value; end
|
123
|
+
alias :error :info
|
125
124
|
end
|
126
125
|
Hero.logger = TestLogger.new
|
127
126
|
|
@@ -136,6 +135,21 @@ describe Hero::Formula do
|
|
136
135
|
assert_equal "HERO after test_formula -> two Context: [1, 2] Options: {:step=>2}", Hero.logger.buffer[3]
|
137
136
|
end
|
138
137
|
|
138
|
+
it "should support logging errors" do
|
139
|
+
class TestLogger
|
140
|
+
attr_reader :info_count, :error_count, :buffer
|
141
|
+
def initialize; @info_count = 0; @error_count = 0; @buffer = []; end
|
142
|
+
def info(value); @info_count += 1; @buffer << value; end
|
143
|
+
def error(value); @error_count += 1; @buffer << value; end
|
144
|
+
end
|
145
|
+
Hero.logger = TestLogger.new
|
146
|
+
Hero::Formula[:test_formula].add_step(:one) { |list, opts| raise Exception.new("fubar") }
|
147
|
+
assert_raise(Exception) { Hero::Formula[:test_formula].run }
|
148
|
+
assert_equal Hero.logger.buffer.length, 2
|
149
|
+
assert_equal Hero.logger.info_count, 1
|
150
|
+
assert_equal Hero.logger.error_count, 1
|
151
|
+
end
|
152
|
+
|
139
153
|
end
|
140
154
|
|
141
155
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hero
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-08-
|
12
|
+
date: 2012-08-27 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! ' Simplify your apps with Hero.
|
15
15
|
|