goon 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +188 -0
- data/lib/goon/competency.rb +41 -0
- data/lib/goon/heist.rb +39 -0
- data/lib/goon/version.rb +3 -0
- data/lib/goon.rb +58 -0
- metadata +112 -0
data/README.md
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
## Goon ##
|
2
|
+
|
3
|
+
Goon is a minion that pulls off heists
|
4
|
+
|
5
|
+
## Release Notes ##
|
6
|
+
|
7
|
+
* 0.0.2 - For example, our naivite caused us to think that we could cut a gem without jumping through hoops.
|
8
|
+
* 0.0.1 - Initial release. Basically usable and spec'd, but probably has some
|
9
|
+
naive implementation.
|
10
|
+
|
11
|
+
## Goons? ##
|
12
|
+
|
13
|
+
That is, a goon object, being taught the proper competencies, will pull off a
|
14
|
+
valid Heist and remember facts related to the process.
|
15
|
+
|
16
|
+
### .new ###
|
17
|
+
|
18
|
+
Creating a Goon is pretty easy, but a Goon created without a Heist is just
|
19
|
+
about worthless. The following will actually do the trick:
|
20
|
+
|
21
|
+
goon = Goon.new
|
22
|
+
|
23
|
+
The following, however, is a lot more useful (or would be if the Heist wasn't
|
24
|
+
just terribly cordial):
|
25
|
+
|
26
|
+
goon = Goon.new(
|
27
|
+
:heist => OpenStruct(
|
28
|
+
:name => 'Heist!!!',
|
29
|
+
:body => 'puts "hello"'
|
30
|
+
)
|
31
|
+
)
|
32
|
+
|
33
|
+
In addition to the :heist option, you can pass in an array of Competency objects
|
34
|
+
with the :competencies option or a hash of facts with the :facts option.
|
35
|
+
|
36
|
+
### #learn_competency ###
|
37
|
+
|
38
|
+
A goon can be taught a new competency. The learn_competency method takes an
|
39
|
+
object conforming to the Competency API and injects it into the goon that is
|
40
|
+
learning. There is also a plural form, learn_competencies, that takes an array
|
41
|
+
of competencies.
|
42
|
+
|
43
|
+
### #remember ###
|
44
|
+
|
45
|
+
A goon can remember facts. The remember method takes a hash where the keys are
|
46
|
+
fact names and the values are the meat of the fact.
|
47
|
+
|
48
|
+
### #recall ###
|
49
|
+
|
50
|
+
A goon can recall facts that it has remembered. The recall method takes a fact name.
|
51
|
+
|
52
|
+
### #forget ###
|
53
|
+
|
54
|
+
A goon can forget facts that it has remembered. The forget method takes a fact name.
|
55
|
+
|
56
|
+
### #run ###
|
57
|
+
|
58
|
+
A goon can pull off a Heist. The run method takes no arguments, but returns the facts that it has remembered when it is done with the job.
|
59
|
+
|
60
|
+
## Heists? ##
|
61
|
+
|
62
|
+
Yeah. Heists. We like metaphors.
|
63
|
+
|
64
|
+
A Heist, when it comes down, is any object that fits this bill:
|
65
|
+
|
66
|
+
* Has a name method that returns a non-empty string
|
67
|
+
* Has a body method that returns a non-empty string
|
68
|
+
|
69
|
+
That said, goon/heist contains the Goon::Heist class that will absolutely always
|
70
|
+
work with Goon, and it also validates itself on creation. Unfortunately, using
|
71
|
+
this class to make a Heist means that exceptions will be raised if an invalid
|
72
|
+
name or body is provided.
|
73
|
+
|
74
|
+
### name ###
|
75
|
+
|
76
|
+
The name of a Heist is just that ... it is a (preferably) unique identifier.
|
77
|
+
|
78
|
+
### body ###
|
79
|
+
|
80
|
+
The body of a Heist is a snippet of code. Most typically,
|
81
|
+
|
82
|
+
## Competencies? ##
|
83
|
+
|
84
|
+
A Competency is a skill that one can teach one's goons. Much like a Heist, a
|
85
|
+
competency can be pretty much any object so long as it fits the following:
|
86
|
+
|
87
|
+
* Has a name method that returns a non-empty string
|
88
|
+
* Has a body method that returns a non-empty string
|
89
|
+
|
90
|
+
If you would like to use our reference Competency, it lives in goon/competency.
|
91
|
+
The same caveats (and then some) apply to this as do to our reference Heist.
|
92
|
+
|
93
|
+
When a Goon learns a Competency, the Goon in question gains an equivalent
|
94
|
+
instance method to said Competency. So, say that we have a Competency named
|
95
|
+
"hello" with the following body:
|
96
|
+
|
97
|
+
puts "hello"
|
98
|
+
|
99
|
+
After learning "hello," my goon will have the following method:
|
100
|
+
|
101
|
+
def hello(options = {})
|
102
|
+
puts "hello"
|
103
|
+
end
|
104
|
+
|
105
|
+
As you can see, a Competency receives a hash of options so that you can pass
|
106
|
+
information into them.
|
107
|
+
|
108
|
+
### name ###
|
109
|
+
|
110
|
+
The name of a Competency is a string that could be used as a Ruby method name.
|
111
|
+
That being the case, it cannot contain spaces, it must be punctuated properly,
|
112
|
+
so on. A good rule of thumb is that if at all possible, make your Competency
|
113
|
+
name a single word without punctuation, et cetera.
|
114
|
+
|
115
|
+
### body ###
|
116
|
+
|
117
|
+
The body of a Competency is the meat of the method that is generated upon
|
118
|
+
learning the Competency. Aside from emptyness, we don't really do any checking
|
119
|
+
on this, but take our word that you absolutely want this to be valid Ruby.
|
120
|
+
|
121
|
+
## Example ##
|
122
|
+
|
123
|
+
<pre>
|
124
|
+
require 'goon'
|
125
|
+
require 'goon/competency'
|
126
|
+
require 'goon/heist'
|
127
|
+
require 'json'
|
128
|
+
|
129
|
+
competencies = []
|
130
|
+
|
131
|
+
# The following are well-formed competencies. Those that are not well-formed
|
132
|
+
# raise Goon::Competency::InvalidCompetency
|
133
|
+
competencies << Goon::Competency.new(
|
134
|
+
:name => 'hello',
|
135
|
+
:description => "Say hello",
|
136
|
+
:body => "puts 'hello'"
|
137
|
+
)
|
138
|
+
|
139
|
+
competencies << Goon::Competency.new(
|
140
|
+
:name => 'parrot',
|
141
|
+
:description => "Repeat after me, Polly",
|
142
|
+
:body => "puts options[:phrase]"
|
143
|
+
)
|
144
|
+
|
145
|
+
heist = Goon::Heist.new(
|
146
|
+
:name => 'The Stinky Teen Job',
|
147
|
+
:body => <<-EOS
|
148
|
+
hello
|
149
|
+
hello
|
150
|
+
hello
|
151
|
+
hello
|
152
|
+
puts 'with the lights down'
|
153
|
+
parrot :phrase => "it's less dangerous"
|
154
|
+
EOS
|
155
|
+
)
|
156
|
+
|
157
|
+
my_goon = Goon.new(:competencies => competencies, :heist => heist)
|
158
|
+
puts "## Running the '#{heist.name}' heist ..."
|
159
|
+
goon_results = my_goon.run
|
160
|
+
puts "## Finished the '#{heist.name}' heist"
|
161
|
+
|
162
|
+
# Since the goon was not instructed to remember anything, an empty hash is
|
163
|
+
# returned.
|
164
|
+
|
165
|
+
puts "## '#{heist.name}' Results: #{goon_results.to_json}\n"
|
166
|
+
|
167
|
+
heist = Goon::Heist.new(
|
168
|
+
:name => 'Remember Remember',
|
169
|
+
:body => <<-EOS
|
170
|
+
puts "remembering the date"
|
171
|
+
remember :when => '1605-11-05'
|
172
|
+
puts "remembering the act"
|
173
|
+
remember :what => 'The Gunpowder (Treason and) Plot'
|
174
|
+
EOS
|
175
|
+
)
|
176
|
+
|
177
|
+
my_goon = Goon.new(:heist => heist)
|
178
|
+
|
179
|
+
puts "## Running the '#{heist.name}' heist ..."
|
180
|
+
|
181
|
+
goon_results = my_goon.run
|
182
|
+
|
183
|
+
puts "## Finished the '#{heist.name}' heist"
|
184
|
+
|
185
|
+
# Since the goon was told to remember things, we get back a non-empty hash.
|
186
|
+
|
187
|
+
puts "## '#{heist.name}' Results: #{goon_results.to_json}"
|
188
|
+
</pre>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'goon'
|
2
|
+
|
3
|
+
class Goon::Competency
|
4
|
+
class InvalidCompetency < Exception
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_accessor :description
|
8
|
+
attr_reader :name, :body
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@name = options[:name].to_s
|
12
|
+
@description = options[:description].to_s || "This competency has no description"
|
13
|
+
@body = options[:body].to_s
|
14
|
+
|
15
|
+
validate_name!
|
16
|
+
validate_body!
|
17
|
+
end
|
18
|
+
|
19
|
+
def name=(new_name)
|
20
|
+
@name = new_name
|
21
|
+
validate_name!
|
22
|
+
end
|
23
|
+
|
24
|
+
def body=(new_body)
|
25
|
+
@body = new_body
|
26
|
+
validate_body!
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def validate_name!
|
32
|
+
raise InvalidCompetency, "name cannot be nil" if @name.nil?
|
33
|
+
raise InvalidCompetency, "name cannot be empty" if @name.gsub(/\s+/, '').empty?
|
34
|
+
raise InvalidCompetency, "'#{@name}' is not a valid method name" unless (@name.to_sym.inspect =~ /[@$\"]/).nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_body!
|
38
|
+
raise InvalidCompetency, "body cannot be nil" if @body.nil?
|
39
|
+
raise InvalidCompetency, "body cannot be blank" if @body.gsub(/\s+/, '').empty?
|
40
|
+
end
|
41
|
+
end
|
data/lib/goon/heist.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'goon'
|
2
|
+
|
3
|
+
class Goon::Heist
|
4
|
+
class InvalidHeist < Exception
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :name, :body
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
@name = options[:name]
|
11
|
+
@description = options[:description]
|
12
|
+
@body = options[:body]
|
13
|
+
|
14
|
+
validate_name!
|
15
|
+
validate_body!
|
16
|
+
end
|
17
|
+
|
18
|
+
def name=(new_name)
|
19
|
+
@name = new_name
|
20
|
+
validate_name!
|
21
|
+
end
|
22
|
+
|
23
|
+
def body=(new_body)
|
24
|
+
@body = new_body
|
25
|
+
validate_body!
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def validate_name!
|
31
|
+
raise InvalidHeist, "name cannot be nil" if @name.nil?
|
32
|
+
raise InvalidHeist, "name cannot be blank" if @name.gsub(/\s+/, '').empty?
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate_body!
|
36
|
+
raise InvalidHeist, "body cannot be nil" if @body.nil?
|
37
|
+
raise InvalidHeist, "body cannot be blank" if @body.gsub(/\s+/, '').empty?
|
38
|
+
end
|
39
|
+
end
|
data/lib/goon/version.rb
ADDED
data/lib/goon.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'goon/version'
|
2
|
+
|
3
|
+
class Goon
|
4
|
+
attr_reader :competencies, :heist, :facts
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
competencies = options[:competencies] || []
|
8
|
+
@competencies = []
|
9
|
+
@heist = options[:heist]
|
10
|
+
@facts = options[:facts] || {}
|
11
|
+
learn_competencies(competencies)
|
12
|
+
end
|
13
|
+
|
14
|
+
def learn_competency(competency)
|
15
|
+
unless @competencies.include? competency
|
16
|
+
instance_eval <<-EOS
|
17
|
+
def #{competency.name}(options = {})
|
18
|
+
#{competency.body}
|
19
|
+
end
|
20
|
+
EOS
|
21
|
+
@competencies << competency
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def learn_competencies(competencies)
|
26
|
+
competencies.each do |competency|
|
27
|
+
learn_competency(competency)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
#def unlearn_competency(name)
|
32
|
+
#instance_eval "undef #{name}"
|
33
|
+
#@competencies.delete(@competencies.select {|x| x.name == name}.first)
|
34
|
+
#end
|
35
|
+
|
36
|
+
#def unlearn_competencies
|
37
|
+
#@competencies.each do |competency|
|
38
|
+
#unlearn_competency(competency.name)
|
39
|
+
#end
|
40
|
+
#end
|
41
|
+
|
42
|
+
def remember(options = {})
|
43
|
+
@facts.merge!(options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def recall(name)
|
47
|
+
@facts[name]
|
48
|
+
end
|
49
|
+
|
50
|
+
def forget(name)
|
51
|
+
@facts.delete(name)
|
52
|
+
end
|
53
|
+
|
54
|
+
def run
|
55
|
+
instance_eval @heist.body
|
56
|
+
@facts
|
57
|
+
end
|
58
|
+
end
|
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: goon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dennis Walters
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-12 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: &10212600 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.9.2
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *10212600
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rdoc
|
27
|
+
requirement: &10212140 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3.8'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *10212140
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &10211680 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.8.0
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *10211680
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: coco
|
49
|
+
requirement: &10211220 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.6'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *10211220
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: mocha
|
60
|
+
requirement: &10210760 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 0.10.5
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *10210760
|
69
|
+
description: ! ' Goon is a minion that pulls off Heists
|
70
|
+
|
71
|
+
'
|
72
|
+
email: pooster@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- lib/goon.rb
|
78
|
+
- lib/goon/version.rb
|
79
|
+
- lib/goon/heist.rb
|
80
|
+
- lib/goon/competency.rb
|
81
|
+
- README.md
|
82
|
+
homepage: https://github.com/ess/goon
|
83
|
+
licenses: []
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options:
|
86
|
+
- --title
|
87
|
+
- goon
|
88
|
+
- --main
|
89
|
+
- README.md
|
90
|
+
- -ri
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 1.8.10
|
109
|
+
signing_key:
|
110
|
+
specification_version: 3
|
111
|
+
summary: A loyal lackey
|
112
|
+
test_files: []
|