angry_mob 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README.md +123 -0
- data/bin/mob +139 -0
- data/lib/angry_mob.rb +28 -0
- data/lib/angry_mob/act.rb +111 -0
- data/lib/angry_mob/act/scheduler.rb +143 -0
- data/lib/angry_mob/action.rb +11 -0
- data/lib/angry_mob/builder.rb +115 -0
- data/lib/angry_mob/extend.rb +10 -0
- data/lib/angry_mob/extend/array.rb +30 -0
- data/lib/angry_mob/extend/blank.rb +108 -0
- data/lib/angry_mob/extend/blankslate.rb +109 -0
- data/lib/angry_mob/extend/dictionary.rb +140 -0
- data/lib/angry_mob/extend/hash.rb +67 -0
- data/lib/angry_mob/extend/object.rb +21 -0
- data/lib/angry_mob/extend/pathname.rb +23 -0
- data/lib/angry_mob/extend/string.rb +8 -0
- data/lib/angry_mob/log.rb +28 -0
- data/lib/angry_mob/mob.rb +77 -0
- data/lib/angry_mob/mob_loader.rb +115 -0
- data/lib/angry_mob/node.rb +44 -0
- data/lib/angry_mob/notifier.rb +76 -0
- data/lib/angry_mob/target.rb +257 -0
- data/lib/angry_mob/target/arguments.rb +71 -0
- data/lib/angry_mob/target/call.rb +57 -0
- data/lib/angry_mob/target/default_resource_locator.rb +11 -0
- data/lib/angry_mob/target/defaults.rb +23 -0
- data/lib/angry_mob/target/mother.rb +66 -0
- data/lib/angry_mob/target/notify.rb +57 -0
- data/lib/angry_mob/target/tracking.rb +96 -0
- data/lib/angry_mob/ui.rb +247 -0
- data/lib/angry_mob/util.rb +11 -0
- data/lib/angry_mob/vendored.rb +8 -0
- data/lib/angry_mob/version.rb +3 -0
- data/vendor/angry_hash/Rakefile +17 -0
- data/vendor/angry_hash/VERSION +1 -0
- data/vendor/angry_hash/angry_hash.gemspec +47 -0
- data/vendor/angry_hash/examples/accessors_eg.rb +46 -0
- data/vendor/angry_hash/examples/creation_eg.rb +43 -0
- data/vendor/angry_hash/examples/dsl.eg.rb +18 -0
- data/vendor/angry_hash/examples/dup_eg.rb +86 -0
- data/vendor/angry_hash/examples/eg_helper.rb +24 -0
- data/vendor/angry_hash/examples/merge_eg.rb +135 -0
- data/vendor/angry_hash/lib/angry_hash.rb +215 -0
- data/vendor/angry_hash/lib/angry_hash/dsl.rb +44 -0
- data/vendor/angry_hash/lib/angry_hash/extension_tracking.rb +12 -0
- data/vendor/angry_hash/lib/angry_hash/merge_string.rb +58 -0
- data/vendor/json/COPYING +58 -0
- data/vendor/json/GPL +340 -0
- data/vendor/json/README +360 -0
- data/vendor/json/lib/json/common.rb +371 -0
- data/vendor/json/lib/json/pure.rb +77 -0
- data/vendor/json/lib/json/pure/generator.rb +443 -0
- data/vendor/json/lib/json/pure/parser.rb +303 -0
- data/vendor/json/lib/json/version.rb +8 -0
- data/vendor/thor/CHANGELOG.rdoc +89 -0
- data/vendor/thor/LICENSE +20 -0
- data/vendor/thor/README.rdoc +297 -0
- data/vendor/thor/Thorfile +69 -0
- data/vendor/thor/bin/rake2thor +86 -0
- data/vendor/thor/bin/thor +6 -0
- data/vendor/thor/lib/thor.rb +244 -0
- data/vendor/thor/lib/thor/actions.rb +275 -0
- data/vendor/thor/lib/thor/actions/create_file.rb +103 -0
- data/vendor/thor/lib/thor/actions/directory.rb +91 -0
- data/vendor/thor/lib/thor/actions/empty_directory.rb +134 -0
- data/vendor/thor/lib/thor/actions/file_manipulation.rb +223 -0
- data/vendor/thor/lib/thor/actions/inject_into_file.rb +104 -0
- data/vendor/thor/lib/thor/base.rb +540 -0
- data/vendor/thor/lib/thor/core_ext/file_binary_read.rb +9 -0
- data/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
- data/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
- data/vendor/thor/lib/thor/error.rb +30 -0
- data/vendor/thor/lib/thor/group.rb +271 -0
- data/vendor/thor/lib/thor/invocation.rb +180 -0
- data/vendor/thor/lib/thor/parser.rb +4 -0
- data/vendor/thor/lib/thor/parser/argument.rb +67 -0
- data/vendor/thor/lib/thor/parser/arguments.rb +150 -0
- data/vendor/thor/lib/thor/parser/option.rb +128 -0
- data/vendor/thor/lib/thor/parser/options.rb +169 -0
- data/vendor/thor/lib/thor/rake_compat.rb +66 -0
- data/vendor/thor/lib/thor/runner.rb +314 -0
- data/vendor/thor/lib/thor/shell.rb +83 -0
- data/vendor/thor/lib/thor/shell/basic.rb +239 -0
- data/vendor/thor/lib/thor/shell/color.rb +108 -0
- data/vendor/thor/lib/thor/task.rb +102 -0
- data/vendor/thor/lib/thor/util.rb +224 -0
- data/vendor/thor/lib/thor/version.rb +3 -0
- data/vendor/thor/spec/actions/create_file_spec.rb +170 -0
- data/vendor/thor/spec/actions/directory_spec.rb +131 -0
- data/vendor/thor/spec/actions/empty_directory_spec.rb +91 -0
- data/vendor/thor/spec/actions/file_manipulation_spec.rb +271 -0
- data/vendor/thor/spec/actions/inject_into_file_spec.rb +135 -0
- data/vendor/thor/spec/actions_spec.rb +292 -0
- data/vendor/thor/spec/base_spec.rb +263 -0
- data/vendor/thor/spec/core_ext/hash_with_indifferent_access_spec.rb +43 -0
- data/vendor/thor/spec/core_ext/ordered_hash_spec.rb +115 -0
- data/vendor/thor/spec/fixtures/application.rb +2 -0
- data/vendor/thor/spec/fixtures/bundle/execute.rb +6 -0
- data/vendor/thor/spec/fixtures/bundle/main.thor +1 -0
- data/vendor/thor/spec/fixtures/doc/%file_name%.rb.tt +1 -0
- data/vendor/thor/spec/fixtures/doc/README +3 -0
- data/vendor/thor/spec/fixtures/doc/config.rb +1 -0
- data/vendor/thor/spec/fixtures/group.thor +90 -0
- data/vendor/thor/spec/fixtures/invoke.thor +112 -0
- data/vendor/thor/spec/fixtures/script.thor +145 -0
- data/vendor/thor/spec/fixtures/task.thor +10 -0
- data/vendor/thor/spec/group_spec.rb +171 -0
- data/vendor/thor/spec/invocation_spec.rb +107 -0
- data/vendor/thor/spec/parser/argument_spec.rb +47 -0
- data/vendor/thor/spec/parser/arguments_spec.rb +64 -0
- data/vendor/thor/spec/parser/option_spec.rb +202 -0
- data/vendor/thor/spec/parser/options_spec.rb +292 -0
- data/vendor/thor/spec/rake_compat_spec.rb +68 -0
- data/vendor/thor/spec/runner_spec.rb +210 -0
- data/vendor/thor/spec/shell/basic_spec.rb +205 -0
- data/vendor/thor/spec/shell/color_spec.rb +41 -0
- data/vendor/thor/spec/shell_spec.rb +34 -0
- data/vendor/thor/spec/spec.opts +1 -0
- data/vendor/thor/spec/spec_helper.rb +54 -0
- data/vendor/thor/spec/task_spec.rb +69 -0
- data/vendor/thor/spec/thor_spec.rb +237 -0
- data/vendor/thor/spec/util_spec.rb +163 -0
- data/vendor/thor/thor.gemspec +120 -0
- metadata +199 -0
@@ -0,0 +1,303 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
module Pure
|
5
|
+
# This class implements the JSON parser that is used to parse a JSON string
|
6
|
+
# into a Ruby data structure.
|
7
|
+
class Parser < StringScanner
|
8
|
+
STRING = /" ((?:[^\x0-\x1f"\\] |
|
9
|
+
# escaped special characters:
|
10
|
+
\\["\\\/bfnrt] |
|
11
|
+
\\u[0-9a-fA-F]{4} |
|
12
|
+
# match all but escaped special characters:
|
13
|
+
\\[\x20-\x21\x23-\x2e\x30-\x5b\x5d-\x61\x63-\x65\x67-\x6d\x6f-\x71\x73\x75-\xff])*)
|
14
|
+
"/nx
|
15
|
+
INTEGER = /(-?0|-?[1-9]\d*)/
|
16
|
+
FLOAT = /(-?
|
17
|
+
(?:0|[1-9]\d*)
|
18
|
+
(?:
|
19
|
+
\.\d+(?i:e[+-]?\d+) |
|
20
|
+
\.\d+ |
|
21
|
+
(?i:e[+-]?\d+)
|
22
|
+
)
|
23
|
+
)/x
|
24
|
+
NAN = /NaN/
|
25
|
+
INFINITY = /Infinity/
|
26
|
+
MINUS_INFINITY = /-Infinity/
|
27
|
+
OBJECT_OPEN = /\{/
|
28
|
+
OBJECT_CLOSE = /\}/
|
29
|
+
ARRAY_OPEN = /\[/
|
30
|
+
ARRAY_CLOSE = /\]/
|
31
|
+
PAIR_DELIMITER = /:/
|
32
|
+
COLLECTION_DELIMITER = /,/
|
33
|
+
TRUE = /true/
|
34
|
+
FALSE = /false/
|
35
|
+
NULL = /null/
|
36
|
+
IGNORE = %r(
|
37
|
+
(?:
|
38
|
+
//[^\n\r]*[\n\r]| # line comments
|
39
|
+
/\* # c-style comments
|
40
|
+
(?:
|
41
|
+
[^*/]| # normal chars
|
42
|
+
/[^*]| # slashes that do not start a nested comment
|
43
|
+
\*[^/]| # asterisks that do not end this comment
|
44
|
+
/(?=\*/) # single slash before this comment's end
|
45
|
+
)*
|
46
|
+
\*/ # the End of this comment
|
47
|
+
|[ \t\r\n]+ # whitespaces: space, horicontal tab, lf, cr
|
48
|
+
)+
|
49
|
+
)mx
|
50
|
+
|
51
|
+
UNPARSED = Object.new
|
52
|
+
|
53
|
+
# Creates a new JSON::Pure::Parser instance for the string _source_.
|
54
|
+
#
|
55
|
+
# It will be configured by the _opts_ hash. _opts_ can have the following
|
56
|
+
# keys:
|
57
|
+
# * *max_nesting*: The maximum depth of nesting allowed in the parsed data
|
58
|
+
# structures. Disable depth checking with :max_nesting => false|nil|0,
|
59
|
+
# it defaults to 19.
|
60
|
+
# * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
|
61
|
+
# defiance of RFC 4627 to be parsed by the Parser. This option defaults
|
62
|
+
# to false.
|
63
|
+
# * *create_additions*: If set to false, the Parser doesn't create
|
64
|
+
# additions even if a matchin class and create_id was found. This option
|
65
|
+
# defaults to true.
|
66
|
+
# * *object_class*: Defaults to Hash
|
67
|
+
# * *array_class*: Defaults to Array
|
68
|
+
def initialize(source, opts = {})
|
69
|
+
if defined?(::Encoding)
|
70
|
+
if source.encoding == Encoding::ASCII_8BIT
|
71
|
+
b = source[0, 4].bytes.to_a
|
72
|
+
source = case
|
73
|
+
when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
|
74
|
+
source.dup.force_encoding(Encoding::UTF_32BE).encode!(Encoding::UTF_8)
|
75
|
+
when b.size >= 4 && b[0] == 0 && b[2] == 0
|
76
|
+
source.dup.force_encoding(Encoding::UTF_16BE).encode!(Encoding::UTF_8)
|
77
|
+
when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
|
78
|
+
source.dup.force_encoding(Encoding::UTF_32LE).encode!(Encoding::UTF_8)
|
79
|
+
when b.size >= 4 && b[1] == 0 && b[3] == 0
|
80
|
+
source.dup.force_encoding(Encoding::UTF_16LE).encode!(Encoding::UTF_8)
|
81
|
+
else
|
82
|
+
source.dup
|
83
|
+
end
|
84
|
+
else
|
85
|
+
source = source.encode(Encoding::UTF_8)
|
86
|
+
end
|
87
|
+
source.force_encoding(Encoding::ASCII_8BIT)
|
88
|
+
else
|
89
|
+
b = source
|
90
|
+
source = case
|
91
|
+
when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
|
92
|
+
JSON.iconv('utf-8', 'utf-32be', b)
|
93
|
+
when b.size >= 4 && b[0] == 0 && b[2] == 0
|
94
|
+
JSON.iconv('utf-8', 'utf-16be', b)
|
95
|
+
when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
|
96
|
+
JSON.iconv('utf-8', 'utf-32le', b)
|
97
|
+
when b.size >= 4 && b[1] == 0 && b[3] == 0
|
98
|
+
JSON.iconv('utf-8', 'utf-16le', b)
|
99
|
+
else
|
100
|
+
b
|
101
|
+
end
|
102
|
+
end
|
103
|
+
super source
|
104
|
+
if !opts.key?(:max_nesting) # defaults to 19
|
105
|
+
@max_nesting = 19
|
106
|
+
elsif opts[:max_nesting]
|
107
|
+
@max_nesting = opts[:max_nesting]
|
108
|
+
else
|
109
|
+
@max_nesting = 0
|
110
|
+
end
|
111
|
+
@allow_nan = !!opts[:allow_nan]
|
112
|
+
ca = true
|
113
|
+
ca = opts[:create_additions] if opts.key?(:create_additions)
|
114
|
+
@create_id = ca ? JSON.create_id : nil
|
115
|
+
@object_class = opts[:object_class] || Hash
|
116
|
+
@array_class = opts[:array_class] || Array
|
117
|
+
end
|
118
|
+
|
119
|
+
alias source string
|
120
|
+
|
121
|
+
# Parses the current JSON string _source_ and returns the complete data
|
122
|
+
# structure as a result.
|
123
|
+
def parse
|
124
|
+
reset
|
125
|
+
obj = nil
|
126
|
+
until eos?
|
127
|
+
case
|
128
|
+
when scan(OBJECT_OPEN)
|
129
|
+
obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
|
130
|
+
@current_nesting = 1
|
131
|
+
obj = parse_object
|
132
|
+
when scan(ARRAY_OPEN)
|
133
|
+
obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
|
134
|
+
@current_nesting = 1
|
135
|
+
obj = parse_array
|
136
|
+
when skip(IGNORE)
|
137
|
+
;
|
138
|
+
else
|
139
|
+
raise ParserError, "source '#{peek(20)}' not in JSON!"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
obj or raise ParserError, "source did not contain any JSON!"
|
143
|
+
obj
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
# Unescape characters in strings.
|
149
|
+
UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
|
150
|
+
UNESCAPE_MAP.update({
|
151
|
+
?" => '"',
|
152
|
+
?\\ => '\\',
|
153
|
+
?/ => '/',
|
154
|
+
?b => "\b",
|
155
|
+
?f => "\f",
|
156
|
+
?n => "\n",
|
157
|
+
?r => "\r",
|
158
|
+
?t => "\t",
|
159
|
+
?u => nil,
|
160
|
+
})
|
161
|
+
|
162
|
+
def parse_string
|
163
|
+
if scan(STRING)
|
164
|
+
return '' if self[1].empty?
|
165
|
+
string = self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
|
166
|
+
if u = UNESCAPE_MAP[$&[1]]
|
167
|
+
u
|
168
|
+
else # \uXXXX
|
169
|
+
bytes = ''
|
170
|
+
i = 0
|
171
|
+
while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
|
172
|
+
bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
|
173
|
+
i += 1
|
174
|
+
end
|
175
|
+
JSON::UTF16toUTF8.iconv(bytes)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
if string.respond_to?(:force_encoding)
|
179
|
+
string.force_encoding(Encoding::UTF_8)
|
180
|
+
end
|
181
|
+
string
|
182
|
+
else
|
183
|
+
UNPARSED
|
184
|
+
end
|
185
|
+
rescue Iconv::Failure => e
|
186
|
+
raise GeneratorError, "Caught #{e.class}: #{e}"
|
187
|
+
end
|
188
|
+
|
189
|
+
def parse_value
|
190
|
+
case
|
191
|
+
when scan(FLOAT)
|
192
|
+
Float(self[1])
|
193
|
+
when scan(INTEGER)
|
194
|
+
Integer(self[1])
|
195
|
+
when scan(TRUE)
|
196
|
+
true
|
197
|
+
when scan(FALSE)
|
198
|
+
false
|
199
|
+
when scan(NULL)
|
200
|
+
nil
|
201
|
+
when (string = parse_string) != UNPARSED
|
202
|
+
string
|
203
|
+
when scan(ARRAY_OPEN)
|
204
|
+
@current_nesting += 1
|
205
|
+
ary = parse_array
|
206
|
+
@current_nesting -= 1
|
207
|
+
ary
|
208
|
+
when scan(OBJECT_OPEN)
|
209
|
+
@current_nesting += 1
|
210
|
+
obj = parse_object
|
211
|
+
@current_nesting -= 1
|
212
|
+
obj
|
213
|
+
when @allow_nan && scan(NAN)
|
214
|
+
NaN
|
215
|
+
when @allow_nan && scan(INFINITY)
|
216
|
+
Infinity
|
217
|
+
when @allow_nan && scan(MINUS_INFINITY)
|
218
|
+
MinusInfinity
|
219
|
+
else
|
220
|
+
UNPARSED
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def parse_array
|
225
|
+
raise NestingError, "nesting of #@current_nesting is too deep" if
|
226
|
+
@max_nesting.nonzero? && @current_nesting > @max_nesting
|
227
|
+
result = @array_class.new
|
228
|
+
delim = false
|
229
|
+
until eos?
|
230
|
+
case
|
231
|
+
when (value = parse_value) != UNPARSED
|
232
|
+
delim = false
|
233
|
+
result << value
|
234
|
+
skip(IGNORE)
|
235
|
+
if scan(COLLECTION_DELIMITER)
|
236
|
+
delim = true
|
237
|
+
elsif match?(ARRAY_CLOSE)
|
238
|
+
;
|
239
|
+
else
|
240
|
+
raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
|
241
|
+
end
|
242
|
+
when scan(ARRAY_CLOSE)
|
243
|
+
if delim
|
244
|
+
raise ParserError, "expected next element in array at '#{peek(20)}'!"
|
245
|
+
end
|
246
|
+
break
|
247
|
+
when skip(IGNORE)
|
248
|
+
;
|
249
|
+
else
|
250
|
+
raise ParserError, "unexpected token in array at '#{peek(20)}'!"
|
251
|
+
end
|
252
|
+
end
|
253
|
+
result
|
254
|
+
end
|
255
|
+
|
256
|
+
def parse_object
|
257
|
+
raise NestingError, "nesting of #@current_nesting is too deep" if
|
258
|
+
@max_nesting.nonzero? && @current_nesting > @max_nesting
|
259
|
+
result = @object_class.new
|
260
|
+
delim = false
|
261
|
+
until eos?
|
262
|
+
case
|
263
|
+
when (string = parse_string) != UNPARSED
|
264
|
+
skip(IGNORE)
|
265
|
+
unless scan(PAIR_DELIMITER)
|
266
|
+
raise ParserError, "expected ':' in object at '#{peek(20)}'!"
|
267
|
+
end
|
268
|
+
skip(IGNORE)
|
269
|
+
unless (value = parse_value).equal? UNPARSED
|
270
|
+
result[string] = value
|
271
|
+
delim = false
|
272
|
+
skip(IGNORE)
|
273
|
+
if scan(COLLECTION_DELIMITER)
|
274
|
+
delim = true
|
275
|
+
elsif match?(OBJECT_CLOSE)
|
276
|
+
;
|
277
|
+
else
|
278
|
+
raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!"
|
279
|
+
end
|
280
|
+
else
|
281
|
+
raise ParserError, "expected value in object at '#{peek(20)}'!"
|
282
|
+
end
|
283
|
+
when scan(OBJECT_CLOSE)
|
284
|
+
if delim
|
285
|
+
raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!"
|
286
|
+
end
|
287
|
+
if @create_id and klassname = result[@create_id]
|
288
|
+
klass = JSON.deep_const_get klassname
|
289
|
+
break unless klass and klass.json_creatable?
|
290
|
+
result = klass.json_create(result)
|
291
|
+
end
|
292
|
+
break
|
293
|
+
when skip(IGNORE)
|
294
|
+
;
|
295
|
+
else
|
296
|
+
raise ParserError, "unexpected token in object at '#{peek(20)}'!"
|
297
|
+
end
|
298
|
+
end
|
299
|
+
result
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
== 0.13, released 2010-02-03
|
2
|
+
|
3
|
+
* Several bug fixes
|
4
|
+
* Decoupled Thor::Group and Thor, so it's easier to vendor
|
5
|
+
* Added check_unknown_options! in case you want error messages to be raised in valid switches.
|
6
|
+
* run(command) should return the results of command
|
7
|
+
|
8
|
+
== 0.12, released 2010-01-02
|
9
|
+
|
10
|
+
* Methods generated by attr_* are automatically not marked as tasks
|
11
|
+
* inject_into_file does not add the same content twice, unless :force is set
|
12
|
+
* Removed rr in favor to rspec mock framework
|
13
|
+
* Improved output for thor -T
|
14
|
+
* [#7] Do not force white color on status
|
15
|
+
* [#8] Yield a block with the filename on directory
|
16
|
+
|
17
|
+
== 0.11, released 2009-07-01
|
18
|
+
|
19
|
+
* Added a rake compatibility layer. It allows you to use spec and rdoc tasks on
|
20
|
+
Thor classes.
|
21
|
+
|
22
|
+
* BACKWARDS INCOMPATIBLE: aliases are not generated automatically anymore
|
23
|
+
since it wrong behavior to the invocation system.
|
24
|
+
|
25
|
+
* thor help now show information about any class/task. All those calls are
|
26
|
+
possible:
|
27
|
+
|
28
|
+
thor help describe
|
29
|
+
thor help describe:amazing
|
30
|
+
|
31
|
+
Or even with default namespaces:
|
32
|
+
|
33
|
+
thor help :spec
|
34
|
+
|
35
|
+
* Thor::Runner now invokes the default task if none is supplied:
|
36
|
+
|
37
|
+
thor describe # invokes the default task, usually help
|
38
|
+
|
39
|
+
* Thor::Runner now works with mappings:
|
40
|
+
|
41
|
+
thor describe -h
|
42
|
+
|
43
|
+
* Added some documentation and code refactoring.
|
44
|
+
|
45
|
+
== 0.9.8, released 2008-10-20
|
46
|
+
|
47
|
+
* Fixed some tiny issues that were introduced lately.
|
48
|
+
|
49
|
+
== 0.9.7, released 2008-10-13
|
50
|
+
|
51
|
+
* Setting global method options on the initialize method works as expected:
|
52
|
+
All other tasks will accept these global options in addition to their own.
|
53
|
+
* Added 'group' notion to Thor task sets (class Thor); by default all tasks
|
54
|
+
are in the 'standard' group. Running 'thor -T' will only show the standard
|
55
|
+
tasks - adding --all will show all tasks. You can also filter on a specific
|
56
|
+
group using the --group option: thor -T --group advanced
|
57
|
+
|
58
|
+
== 0.9.6, released 2008-09-13
|
59
|
+
|
60
|
+
* Generic improvements
|
61
|
+
|
62
|
+
== 0.9.5, released 2008-08-27
|
63
|
+
|
64
|
+
* Improve Windows compatibility
|
65
|
+
* Update (incorrect) README and task.thor sample file
|
66
|
+
* Options hash is now frozen (once returned)
|
67
|
+
* Allow magic predicates on options object. For instance: `options.force?`
|
68
|
+
* Add support for :numeric type
|
69
|
+
* BACKWARDS INCOMPATIBLE: Refactor Thor::Options. You cannot access shorthand forms in options hash anymore (for instance, options[:f])
|
70
|
+
* Allow specifying optional args with default values: method_options(:user => "mislav")
|
71
|
+
* Don't write options for nil or false values. This allows, for example, turning color off when running specs.
|
72
|
+
* Exit with the status of the spec command to help CI stuff out some.
|
73
|
+
|
74
|
+
== 0.9.4, released 2008-08-13
|
75
|
+
|
76
|
+
* Try to add Windows compatibility.
|
77
|
+
* BACKWARDS INCOMPATIBLE: options hash is now accessed as a property in your class and is not passed as last argument anymore
|
78
|
+
* Allow options at the beginning of the argument list as well as the end.
|
79
|
+
* Make options available with symbol keys in addition to string keys.
|
80
|
+
* Allow true to be passed to Thor#method_options to denote a boolean option.
|
81
|
+
* If loading a thor file fails, don't give up, just print a warning and keep going.
|
82
|
+
* Make sure that we re-raise errors if they happened further down the pipe than we care about.
|
83
|
+
* Only delete the old file on updating when the installation of the new one is a success
|
84
|
+
* Make it Ruby 1.8.5 compatible.
|
85
|
+
* Don't raise an error if a boolean switch is defined multiple times.
|
86
|
+
* Thor::Options now doesn't parse through things that look like options but aren't.
|
87
|
+
* Add URI detection to install task, and make sure we don't append ".thor" to URIs
|
88
|
+
* Add rake2thor to the gem binfiles.
|
89
|
+
* Make sure local Thorfiles override system-wide ones.
|
data/vendor/thor/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Yehuda Katz
|
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,297 @@
|
|
1
|
+
= thor
|
2
|
+
|
3
|
+
Map options to a class. Simply create a class with the appropriate annotations
|
4
|
+
and have options automatically map to functions and parameters.
|
5
|
+
|
6
|
+
Example:
|
7
|
+
|
8
|
+
class App < Thor # [1]
|
9
|
+
map "-L" => :list # [2]
|
10
|
+
|
11
|
+
desc "install APP_NAME", "install one of the available apps" # [3]
|
12
|
+
method_options :force => :boolean, :alias => :string # [4]
|
13
|
+
def install(name)
|
14
|
+
user_alias = options[:alias]
|
15
|
+
if options.force?
|
16
|
+
# do something
|
17
|
+
end
|
18
|
+
# other code
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "list [SEARCH]", "list all of the available apps, limited by SEARCH"
|
22
|
+
def list(search="")
|
23
|
+
# list everything
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Thor automatically maps commands as such:
|
28
|
+
|
29
|
+
thor app:install myname --force
|
30
|
+
|
31
|
+
That gets converted to:
|
32
|
+
|
33
|
+
App.new.install("myname")
|
34
|
+
# with {'force' => true} as options hash
|
35
|
+
|
36
|
+
1. Inherit from Thor to turn a class into an option mapper
|
37
|
+
2. Map additional non-valid identifiers to specific methods. In this case, convert -L to :list
|
38
|
+
3. Describe the method immediately below. The first parameter is the usage information, and the second parameter is the description
|
39
|
+
4. Provide any additional options that will be available the instance method options.
|
40
|
+
|
41
|
+
== Types for <tt>method_options</tt>
|
42
|
+
|
43
|
+
* :boolean - is parsed as <tt>--option</tt> or <tt>--option=true</tt>
|
44
|
+
* :string - is parsed as <tt>--option=VALUE</tt>
|
45
|
+
* :numeric - is parsed as <tt>--option=N</tt>
|
46
|
+
* :array - is parsed as <tt>--option=one two three</tt>
|
47
|
+
* :hash - is parsed as <tt>--option=name:string age:integer</tt>
|
48
|
+
|
49
|
+
Besides, method_option allows a default value to be given, examples:
|
50
|
+
|
51
|
+
method_options :force => false
|
52
|
+
#=> Creates a boolean option with default value false
|
53
|
+
|
54
|
+
method_options :alias => "bar"
|
55
|
+
#=> Creates a string option with default value "bar"
|
56
|
+
|
57
|
+
method_options :threshold => 3.0
|
58
|
+
#=> Creates a numeric option with default value 3.0
|
59
|
+
|
60
|
+
You can also supply <tt>:option => :required</tt> to mark an option as required. The
|
61
|
+
type is assumed to be string. If you want a required hash with default values
|
62
|
+
as option, you can use <tt>method_option</tt> which uses a more declarative style:
|
63
|
+
|
64
|
+
method_option :attributes, :type => :hash, :default => {}, :required => true
|
65
|
+
|
66
|
+
All arguments can be set to nil (except required arguments), by suppling a no or
|
67
|
+
skip variant. For example:
|
68
|
+
|
69
|
+
thor app name --no-attributes
|
70
|
+
|
71
|
+
In previous versions, aliases for options were created automatically, but now
|
72
|
+
they should be explicit. You can supply aliases in both short and declarative
|
73
|
+
styles:
|
74
|
+
|
75
|
+
method_options %w( force -f ) => :boolean
|
76
|
+
|
77
|
+
Or:
|
78
|
+
|
79
|
+
method_option :force, :type => :boolean, :aliases => "-f"
|
80
|
+
|
81
|
+
You can supply as many aliases as you want.
|
82
|
+
|
83
|
+
NOTE: Type :optional available in Thor 0.9.0 was deprecated. Use :string or :boolean instead.
|
84
|
+
|
85
|
+
== Namespaces
|
86
|
+
|
87
|
+
By default, your Thor tasks are invoked using Ruby namespace. In the example
|
88
|
+
above, tasks are invoked as:
|
89
|
+
|
90
|
+
thor app:install name --force
|
91
|
+
|
92
|
+
However, you could namespace your class as:
|
93
|
+
|
94
|
+
module Sinatra
|
95
|
+
class App < Thor
|
96
|
+
# tasks
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
And then you should invoke your tasks as:
|
101
|
+
|
102
|
+
thor sinatra:app:install name --force
|
103
|
+
|
104
|
+
If desired, you can change the namespace:
|
105
|
+
|
106
|
+
module Sinatra
|
107
|
+
class App < Thor
|
108
|
+
namespace :myapp
|
109
|
+
# tasks
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
And then your tasks hould be invoked as:
|
114
|
+
|
115
|
+
thor myapp:install name --force
|
116
|
+
|
117
|
+
== Invocations
|
118
|
+
|
119
|
+
Thor comes with a invocation-dependency system as well which allows a task to be
|
120
|
+
invoked only once. For example:
|
121
|
+
|
122
|
+
class Counter < Thor
|
123
|
+
desc "one", "Prints 1, 2, 3"
|
124
|
+
def one
|
125
|
+
puts 1
|
126
|
+
invoke :two
|
127
|
+
invoke :three
|
128
|
+
end
|
129
|
+
|
130
|
+
desc "two", "Prints 2, 3"
|
131
|
+
def two
|
132
|
+
puts 2
|
133
|
+
invoke :three
|
134
|
+
end
|
135
|
+
|
136
|
+
desc "three", "Prints 3"
|
137
|
+
def three
|
138
|
+
puts 3
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
When invoking the task one:
|
143
|
+
|
144
|
+
thor counter:one
|
145
|
+
|
146
|
+
The output is "1 2 3", which means that the three task was invoked only once.
|
147
|
+
You can even invoke tasks from another class, so be sure to check the
|
148
|
+
documentation[http://rdoc.info/rdoc/wycats/thor/blob/f939a3e8a854616784cac1dcff04ef4f3ee5f7ff/Thor.html].
|
149
|
+
|
150
|
+
== Thor::Group
|
151
|
+
|
152
|
+
Thor has a special class called Thor::Group. The main difference to Thor class
|
153
|
+
is that it invokes all tasks at once. The example above could be rewritten in
|
154
|
+
Thor::Group as this:
|
155
|
+
|
156
|
+
class Counter < Thor::Group
|
157
|
+
desc "Prints 1, 2, 3"
|
158
|
+
|
159
|
+
def one
|
160
|
+
puts 1
|
161
|
+
end
|
162
|
+
|
163
|
+
def two
|
164
|
+
puts 2
|
165
|
+
end
|
166
|
+
|
167
|
+
def three
|
168
|
+
puts 3
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
When invoked:
|
173
|
+
|
174
|
+
thor counter
|
175
|
+
|
176
|
+
It prints "1 2 3" as well. Notice you should describe (using the method <tt>desc</tt>)
|
177
|
+
only the class and not each task anymore. Thor::Group is a great tool to create
|
178
|
+
generators, since you can define several steps which are invoked in the order they
|
179
|
+
are defined (Thor::Group is the tool use in generators in Rails 3.0).
|
180
|
+
|
181
|
+
Besides, Thor::Group can parse arguments and options as Thor tasks:
|
182
|
+
|
183
|
+
class Counter < Thor::Group
|
184
|
+
# number will be available as attr_accessor
|
185
|
+
argument :number, :type => :numeric, :desc => "The number to start counting"
|
186
|
+
desc "Prints the 'number' given upto 'number+2'"
|
187
|
+
|
188
|
+
def one
|
189
|
+
puts number + 0
|
190
|
+
end
|
191
|
+
|
192
|
+
def two
|
193
|
+
puts number + 1
|
194
|
+
end
|
195
|
+
|
196
|
+
def three
|
197
|
+
puts number + 2
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
The counter above expects one parameter and has the folling outputs:
|
202
|
+
|
203
|
+
thor counter 5
|
204
|
+
# Prints "5 6 7"
|
205
|
+
|
206
|
+
thor counter 11
|
207
|
+
# Prints "11 12 13"
|
208
|
+
|
209
|
+
You can also give options to Thor::Group, but instead of using <tt>method_option</tt>
|
210
|
+
and <tt>method_options</tt>, you should use <tt>class_option</tt> and <tt>class_options</tt>.
|
211
|
+
Both argument and class_options methods are available to Thor class as well.
|
212
|
+
|
213
|
+
== Actions
|
214
|
+
|
215
|
+
Thor comes with several actions which helps with script and generator tasks. You
|
216
|
+
might be familiar with them since some came from Rails Templates. They are:
|
217
|
+
<tt>say</tt>, <tt>ask</tt>, <tt>yes?</tt>, <tt>no?</tt>, <tt>add_file</tt>,
|
218
|
+
<tt>remove_file</tt>, <tt>copy_file</tt>, <tt>template</tt>, <tt>directory</tt>,
|
219
|
+
<tt>inside</tt>, <tt>run</tt>, <tt>inject_into_file</tt> and a couple more.
|
220
|
+
|
221
|
+
To use them, you just need to include Thor::Actions in your Thor classes:
|
222
|
+
|
223
|
+
class App < Thor
|
224
|
+
include Thor::Actions
|
225
|
+
# tasks
|
226
|
+
end
|
227
|
+
|
228
|
+
Some actions like copy file requires that a class method called source_root is
|
229
|
+
defined in your class. This is the directory where your templates should be
|
230
|
+
placed. Be sure to check the documentation on actions[http://rdoc.info/rdoc/wycats/thor/blob/f939a3e8a854616784cac1dcff04ef4f3ee5f7ff/Thor/Actions.html].
|
231
|
+
|
232
|
+
== Generators
|
233
|
+
|
234
|
+
A great use for Thor is creating custom generators. Combining Thor::Group,
|
235
|
+
Thor::Actions and ERB templates makes this very easy. Here is an example:
|
236
|
+
|
237
|
+
class Newgem < Thor::Group
|
238
|
+
include Thor::Actions
|
239
|
+
|
240
|
+
# Define arguments and options
|
241
|
+
argument :name
|
242
|
+
class_option :test_framework, :default => :test_unit
|
243
|
+
|
244
|
+
def self.source_root
|
245
|
+
File.dirname(__FILE__)
|
246
|
+
end
|
247
|
+
|
248
|
+
def create_lib_file
|
249
|
+
template('templates/newgem.tt', "#{name}/lib/#{name}.rb")
|
250
|
+
end
|
251
|
+
|
252
|
+
def create_test_file
|
253
|
+
test = options[:test_framework] == "rspec" ? :spec : :test
|
254
|
+
create_file "#{name}/#{test}/#{name}_#{test}.rb"
|
255
|
+
end
|
256
|
+
|
257
|
+
def copy_licence
|
258
|
+
if yes?("Use MIT license?")
|
259
|
+
# Make a copy of the MITLICENSE file at the source root
|
260
|
+
copy_file "MITLICENSE", "#{name}/MITLICENSE"
|
261
|
+
else
|
262
|
+
say "Shame on you…", :red
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
Doing a <tt>thor -T</tt> will show how to run our generator. It should read:
|
268
|
+
<tt>thor newgem NAME</tt>. This shows that we have to supply a NAME
|
269
|
+
argument for our generator to run.
|
270
|
+
|
271
|
+
The <tt>create_lib_file</tt> uses an ERB template. This is what it looks like:
|
272
|
+
|
273
|
+
class <%= name.capitalize %>
|
274
|
+
end
|
275
|
+
|
276
|
+
The arguments that you set in your generator will automatically be passed in
|
277
|
+
when <tt>template</tt> gets called. Be sure to read the documentation[http://rdoc.info/rdoc/wycats/thor/blob/f939a3e8a854616784cac1dcff04ef4f3ee5f7ff/Thor/Actions.html] for
|
278
|
+
more options.
|
279
|
+
|
280
|
+
Running the generator with <tt>thor newgem devise</tt> will
|
281
|
+
create two files: "devise/lib/devise.rb",
|
282
|
+
"devise/test/devise_test.rb". The user will then be prompt (with the
|
283
|
+
use of the method <tt>yes?</tt>) if he wants to copy the MITLICENSE. If you
|
284
|
+
want to change the test framework, you can add the option:
|
285
|
+
<tt>thor newgem devise --test-framework=rspec</tt>
|
286
|
+
This will generate: "devise/lib/devise.rb" and
|
287
|
+
"devise/spec/devise_spec.rb".
|
288
|
+
|
289
|
+
== Further Reading
|
290
|
+
|
291
|
+
Thor has many scripting possibilities beyond these examples. Be sure to read
|
292
|
+
through the documentation[http://rdoc.info/rdoc/wycats/thor/blob/f939a3e8a854616784cac1dcff04ef4f3ee5f7ff/Thor.html] and specs[http://github.com/wycats/thor/tree/master/spec/] to get a better understanding of all the
|
293
|
+
options Thor offers.
|
294
|
+
|
295
|
+
== License
|
296
|
+
|
297
|
+
See MIT LICENSE.
|