dotum 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.groc.json +6 -0
  4. data/.rspec +4 -0
  5. data/.simplecov +5 -0
  6. data/.travis.yml +15 -0
  7. data/CONTRIBUTING.md +63 -0
  8. data/Gemfile +59 -0
  9. data/Guardfile +30 -0
  10. data/MIT-LICENSE.md +21 -0
  11. data/README.md +24 -0
  12. data/Rakefile +15 -0
  13. data/bin/dotum +7 -0
  14. data/data/default_rules.dotum +44 -0
  15. data/dotum.gemspec +19 -0
  16. data/extern/json/CHANGES.md +9 -0
  17. data/extern/json/COPYING +58 -0
  18. data/extern/json/README.rdoc +358 -0
  19. data/extern/json/lib/json.rb +62 -0
  20. data/extern/json/lib/json/.DS_Store +0 -0
  21. data/extern/json/lib/json/add/bigdecimal.rb +28 -0
  22. data/extern/json/lib/json/add/complex.rb +22 -0
  23. data/extern/json/lib/json/add/core.rb +11 -0
  24. data/extern/json/lib/json/add/date.rb +34 -0
  25. data/extern/json/lib/json/add/date_time.rb +50 -0
  26. data/extern/json/lib/json/add/exception.rb +31 -0
  27. data/extern/json/lib/json/add/ostruct.rb +31 -0
  28. data/extern/json/lib/json/add/range.rb +29 -0
  29. data/extern/json/lib/json/add/rational.rb +22 -0
  30. data/extern/json/lib/json/add/regexp.rb +30 -0
  31. data/extern/json/lib/json/add/struct.rb +30 -0
  32. data/extern/json/lib/json/add/symbol.rb +25 -0
  33. data/extern/json/lib/json/add/time.rb +38 -0
  34. data/extern/json/lib/json/common.rb +487 -0
  35. data/extern/json/lib/json/generic_object.rb +70 -0
  36. data/extern/json/lib/json/pure.rb +21 -0
  37. data/extern/json/lib/json/pure/generator.rb +522 -0
  38. data/extern/json/lib/json/pure/parser.rb +359 -0
  39. data/extern/json/lib/json/version.rb +8 -0
  40. data/lib/dotum.rb +11 -0
  41. data/lib/dotum/abstract_rules.rb +5 -0
  42. data/lib/dotum/abstract_rules/base.rb +56 -0
  43. data/lib/dotum/abstract_rules/globbable_files.rb +51 -0
  44. data/lib/dotum/abstract_rules/options_base.rb +33 -0
  45. data/lib/dotum/autoload_convention.rb +34 -0
  46. data/lib/dotum/cli.rb +35 -0
  47. data/lib/dotum/context.rb +55 -0
  48. data/lib/dotum/externs/json.rb +9 -0
  49. data/lib/dotum/logger.rb +50 -0
  50. data/lib/dotum/options_context.rb +21 -0
  51. data/lib/dotum/rule_dsl.rb +73 -0
  52. data/lib/dotum/rule_options_dsl.rb +116 -0
  53. data/lib/dotum/rule_runner.rb +16 -0
  54. data/lib/dotum/rules.rb +5 -0
  55. data/lib/dotum/rules/cd.rb +23 -0
  56. data/lib/dotum/rules/download.rb +32 -0
  57. data/lib/dotum/rules/link.rb +22 -0
  58. data/lib/dotum/rules/repo.rb +65 -0
  59. data/lib/dotum/rules/require_extension.rb +42 -0
  60. data/lib/dotum/rules/run.rb +23 -0
  61. data/lib/dotum/rules/use.rb +33 -0
  62. data/lib/dotum/rules/use_repo.rb +58 -0
  63. data/lib/dotum/standard_options.rb +5 -0
  64. data/lib/dotum/standard_options/destination.rb +22 -0
  65. data/lib/dotum/util.rb +5 -0
  66. data/lib/dotum/util/ansi_colors.rb +26 -0
  67. data/lib/dotum/util/path.rb +120 -0
  68. data/lib/dotum/version.rb +5 -0
  69. data/spec/fixtures/autoload_convention/abc_one_two_three.rb +7 -0
  70. data/spec/fixtures/autoload_convention/allcaps.rb +7 -0
  71. data/spec/fixtures/autoload_convention/mismatched.rb +3 -0
  72. data/spec/fixtures/autoload_convention/multi_token.rb +7 -0
  73. data/spec/fixtures/autoload_convention/single.rb +7 -0
  74. data/spec/fixtures/autoload_convention/string.rb +7 -0
  75. data/spec/spec_helper.rb +76 -0
  76. data/spec/unit/dotum/autoload_convention/const_missing_spec.rb +57 -0
  77. data/tasks/console.rake +9 -0
  78. data/tasks/spec.rake +7 -0
  79. data/tasks/spec/ci.rake +16 -0
  80. data/tasks/spec/coverage.rake +19 -0
  81. data/tasks/spec/mutate.rake +71 -0
  82. metadata +123 -0
@@ -0,0 +1,359 @@
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 100.
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
+ # * *symbolize_names*: If set to true, returns symbols for the names
64
+ # (keys) in a JSON object. Otherwise strings are returned, which is also
65
+ # the default.
66
+ # * *create_additions*: If set to true, the Parser creates
67
+ # additions when if a matching class and create_id was found. This
68
+ # option defaults to false.
69
+ # * *object_class*: Defaults to Hash
70
+ # * *array_class*: Defaults to Array
71
+ # * *quirks_mode*: Enables quirks_mode for parser, that is for example
72
+ # parsing single JSON values instead of documents is possible.
73
+ def initialize(source, opts = {})
74
+ opts ||= {}
75
+ unless @quirks_mode = opts[:quirks_mode]
76
+ source = convert_encoding source
77
+ end
78
+ super source
79
+ if !opts.key?(:max_nesting) # defaults to 100
80
+ @max_nesting = 100
81
+ elsif opts[:max_nesting]
82
+ @max_nesting = opts[:max_nesting]
83
+ else
84
+ @max_nesting = 0
85
+ end
86
+ @allow_nan = !!opts[:allow_nan]
87
+ @symbolize_names = !!opts[:symbolize_names]
88
+ if opts.key?(:create_additions)
89
+ @create_additions = !!opts[:create_additions]
90
+ else
91
+ @create_additions = false
92
+ end
93
+ @create_id = @create_additions ? JSON.create_id : nil
94
+ @object_class = opts[:object_class] || Hash
95
+ @array_class = opts[:array_class] || Array
96
+ @match_string = opts[:match_string]
97
+ end
98
+
99
+ alias source string
100
+
101
+ def quirks_mode?
102
+ !!@quirks_mode
103
+ end
104
+
105
+ def reset
106
+ super
107
+ @current_nesting = 0
108
+ end
109
+
110
+ # Parses the current JSON string _source_ and returns the complete data
111
+ # structure as a result.
112
+ def parse
113
+ reset
114
+ obj = nil
115
+ if @quirks_mode
116
+ while !eos? && skip(IGNORE)
117
+ end
118
+ if eos?
119
+ raise ParserError, "source did not contain any JSON!"
120
+ else
121
+ obj = parse_value
122
+ obj == UNPARSED and raise ParserError, "source did not contain any JSON!"
123
+ end
124
+ else
125
+ until eos?
126
+ case
127
+ when scan(OBJECT_OPEN)
128
+ obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
129
+ @current_nesting = 1
130
+ obj = parse_object
131
+ when scan(ARRAY_OPEN)
132
+ obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
133
+ @current_nesting = 1
134
+ obj = parse_array
135
+ when skip(IGNORE)
136
+ ;
137
+ else
138
+ raise ParserError, "source '#{peek(20)}' not in JSON!"
139
+ end
140
+ end
141
+ obj or raise ParserError, "source did not contain any JSON!"
142
+ end
143
+ obj
144
+ end
145
+
146
+ private
147
+
148
+ def convert_encoding(source)
149
+ if source.respond_to?(:to_str)
150
+ source = source.to_str
151
+ else
152
+ raise TypeError, "#{source.inspect} is not like a string"
153
+ end
154
+ if defined?(::Encoding)
155
+ if source.encoding == ::Encoding::ASCII_8BIT
156
+ b = source[0, 4].bytes.to_a
157
+ source =
158
+ case
159
+ when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
160
+ source.dup.force_encoding(::Encoding::UTF_32BE).encode!(::Encoding::UTF_8)
161
+ when b.size >= 4 && b[0] == 0 && b[2] == 0
162
+ source.dup.force_encoding(::Encoding::UTF_16BE).encode!(::Encoding::UTF_8)
163
+ when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
164
+ source.dup.force_encoding(::Encoding::UTF_32LE).encode!(::Encoding::UTF_8)
165
+ when b.size >= 4 && b[1] == 0 && b[3] == 0
166
+ source.dup.force_encoding(::Encoding::UTF_16LE).encode!(::Encoding::UTF_8)
167
+ else
168
+ source.dup
169
+ end
170
+ else
171
+ source = source.encode(::Encoding::UTF_8)
172
+ end
173
+ source.force_encoding(::Encoding::ASCII_8BIT)
174
+ else
175
+ b = source
176
+ source =
177
+ case
178
+ when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
179
+ JSON.iconv('utf-8', 'utf-32be', b)
180
+ when b.size >= 4 && b[0] == 0 && b[2] == 0
181
+ JSON.iconv('utf-8', 'utf-16be', b)
182
+ when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
183
+ JSON.iconv('utf-8', 'utf-32le', b)
184
+ when b.size >= 4 && b[1] == 0 && b[3] == 0
185
+ JSON.iconv('utf-8', 'utf-16le', b)
186
+ else
187
+ b
188
+ end
189
+ end
190
+ source
191
+ end
192
+
193
+ # Unescape characters in strings.
194
+ UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
195
+ UNESCAPE_MAP.update({
196
+ ?" => '"',
197
+ ?\\ => '\\',
198
+ ?/ => '/',
199
+ ?b => "\b",
200
+ ?f => "\f",
201
+ ?n => "\n",
202
+ ?r => "\r",
203
+ ?t => "\t",
204
+ ?u => nil,
205
+ })
206
+
207
+ EMPTY_8BIT_STRING = ''
208
+ if ::String.method_defined?(:encode)
209
+ EMPTY_8BIT_STRING.force_encoding Encoding::ASCII_8BIT
210
+ end
211
+
212
+ def parse_string
213
+ if scan(STRING)
214
+ return '' if self[1].empty?
215
+ string = self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
216
+ if u = UNESCAPE_MAP[$&[1]]
217
+ u
218
+ else # \uXXXX
219
+ bytes = EMPTY_8BIT_STRING.dup
220
+ i = 0
221
+ while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
222
+ bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
223
+ i += 1
224
+ end
225
+ JSON.iconv('utf-8', 'utf-16be', bytes)
226
+ end
227
+ end
228
+ if string.respond_to?(:force_encoding)
229
+ string.force_encoding(::Encoding::UTF_8)
230
+ end
231
+ if @create_additions and @match_string
232
+ for (regexp, klass) in @match_string
233
+ klass.json_creatable? or next
234
+ string =~ regexp and return klass.json_create(string)
235
+ end
236
+ end
237
+ string
238
+ else
239
+ UNPARSED
240
+ end
241
+ rescue => e
242
+ raise ParserError, "Caught #{e.class} at '#{peek(20)}': #{e}"
243
+ end
244
+
245
+ def parse_value
246
+ case
247
+ when scan(FLOAT)
248
+ Float(self[1])
249
+ when scan(INTEGER)
250
+ Integer(self[1])
251
+ when scan(TRUE)
252
+ true
253
+ when scan(FALSE)
254
+ false
255
+ when scan(NULL)
256
+ nil
257
+ when (string = parse_string) != UNPARSED
258
+ string
259
+ when scan(ARRAY_OPEN)
260
+ @current_nesting += 1
261
+ ary = parse_array
262
+ @current_nesting -= 1
263
+ ary
264
+ when scan(OBJECT_OPEN)
265
+ @current_nesting += 1
266
+ obj = parse_object
267
+ @current_nesting -= 1
268
+ obj
269
+ when @allow_nan && scan(NAN)
270
+ NaN
271
+ when @allow_nan && scan(INFINITY)
272
+ Infinity
273
+ when @allow_nan && scan(MINUS_INFINITY)
274
+ MinusInfinity
275
+ else
276
+ UNPARSED
277
+ end
278
+ end
279
+
280
+ def parse_array
281
+ raise NestingError, "nesting of #@current_nesting is too deep" if
282
+ @max_nesting.nonzero? && @current_nesting > @max_nesting
283
+ result = @array_class.new
284
+ delim = false
285
+ until eos?
286
+ case
287
+ when (value = parse_value) != UNPARSED
288
+ delim = false
289
+ result << value
290
+ skip(IGNORE)
291
+ if scan(COLLECTION_DELIMITER)
292
+ delim = true
293
+ elsif match?(ARRAY_CLOSE)
294
+ ;
295
+ else
296
+ raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
297
+ end
298
+ when scan(ARRAY_CLOSE)
299
+ if delim
300
+ raise ParserError, "expected next element in array at '#{peek(20)}'!"
301
+ end
302
+ break
303
+ when skip(IGNORE)
304
+ ;
305
+ else
306
+ raise ParserError, "unexpected token in array at '#{peek(20)}'!"
307
+ end
308
+ end
309
+ result
310
+ end
311
+
312
+ def parse_object
313
+ raise NestingError, "nesting of #@current_nesting is too deep" if
314
+ @max_nesting.nonzero? && @current_nesting > @max_nesting
315
+ result = @object_class.new
316
+ delim = false
317
+ until eos?
318
+ case
319
+ when (string = parse_string) != UNPARSED
320
+ skip(IGNORE)
321
+ unless scan(PAIR_DELIMITER)
322
+ raise ParserError, "expected ':' in object at '#{peek(20)}'!"
323
+ end
324
+ skip(IGNORE)
325
+ unless (value = parse_value).equal? UNPARSED
326
+ result[@symbolize_names ? string.to_sym : string] = value
327
+ delim = false
328
+ skip(IGNORE)
329
+ if scan(COLLECTION_DELIMITER)
330
+ delim = true
331
+ elsif match?(OBJECT_CLOSE)
332
+ ;
333
+ else
334
+ raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!"
335
+ end
336
+ else
337
+ raise ParserError, "expected value in object at '#{peek(20)}'!"
338
+ end
339
+ when scan(OBJECT_CLOSE)
340
+ if delim
341
+ raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!"
342
+ end
343
+ if @create_additions and klassname = result[@create_id]
344
+ klass = JSON.deep_const_get klassname
345
+ break unless klass and klass.json_creatable?
346
+ result = klass.json_create(result)
347
+ end
348
+ break
349
+ when skip(IGNORE)
350
+ ;
351
+ else
352
+ raise ParserError, "unexpected token in object at '#{peek(20)}'!"
353
+ end
354
+ end
355
+ result
356
+ end
357
+ end
358
+ end
359
+ end
@@ -0,0 +1,8 @@
1
+ module JSON
2
+ # JSON version
3
+ VERSION = '1.8.0'
4
+ VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
5
+ VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
+ VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
7
+ VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
8
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ require "dotum/autoload_convention"
4
+
5
+ module Dotum
6
+ extend Dotum::AutoloadConvention
7
+
8
+ LIB_PATH = Dotum::Util::Path.new("..", __FILE__)
9
+ DATA_PATH = Dotum::Util::Path.new("../../data", __FILE__)
10
+ EXTERN_PATH = Dotum::Util::Path.new("../../extern", __FILE__)
11
+ end
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ module Dotum::AbstractRules
4
+ extend Dotum::AutoloadConvention
5
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+
3
+ class Dotum::AbstractRules::Base
4
+ extend Dotum::RuleOptionsDSL
5
+ include Dotum::RuleDSL
6
+
7
+ def self.exec(context, *args, &block)
8
+ new(context, *args, &block).exec
9
+ end
10
+
11
+ def self.pretty
12
+ @pretty ||= name.split('::').last.gsub(/([^A-Z])([A-Z]+)/, "\\1_\\2").downcase
13
+ end
14
+
15
+ def initialize(context)
16
+ @context = context.child
17
+ end
18
+
19
+ def exec
20
+ context.logger.start_rule(self)
21
+
22
+ status, reason = catch(:finish_rule) do
23
+ preprocess
24
+ execute
25
+
26
+ success!
27
+ end
28
+
29
+ context.logger.finish_rule(self, status, reason)
30
+
31
+ if status == :failure
32
+ raise "Rule failed: #{reason}"
33
+ end
34
+
35
+ self
36
+ end
37
+
38
+ attr_reader :context
39
+
40
+ def pretty_subject
41
+ raise NotImplementedError, "#{self.class}#pretty_subject"
42
+ end
43
+
44
+ protected
45
+
46
+ def preprocess
47
+ self.class.preprocessor_methods.each do |sym|
48
+ send(sym)
49
+ end
50
+ end
51
+
52
+ def execute
53
+ raise NotImplementedError, "#{self.class}#execute"
54
+ end
55
+
56
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ class Dotum::AbstractRules::GlobbableFiles < Dotum::AbstractRules::OptionsBase
4
+
5
+ GLOB_MATCHER = /\*/
6
+ DIR_MATCHER = /[\/\\]$/
7
+
8
+ shorthand :source => :destination
9
+
10
+ required(:source) { |v| context.package_dir.join(v) }
11
+ standard :destination
12
+ # By default, we ignore certain special paths, such as source control state.
13
+ optional :ignore_pattern, /(^|[\/\\])(\.git|\.svn)([\/\\]|$)|rules.dotum$/
14
+
15
+ def self.expand_options(context, options)
16
+ source = options[:source]
17
+ destination = options[:destination]
18
+
19
+ source_is_glob = GLOB_MATCHER === source
20
+ target_is_dir = DIR_MATCHER === destination if destination
21
+ if source_is_glob && destination && !target_is_dir
22
+ raise "target path must be a directory when linking a glob expression."
23
+ end
24
+
25
+ sources = context.package_dir.relative_glob(source, &:file?)
26
+ if sources.size > 1 && destination && !target_is_dir
27
+ raise "Bug! target path is a file, but we globbed multiple sources!"
28
+ end
29
+
30
+ sources.reject! { |p| options[:ignore_pattern] =~ p }
31
+
32
+ sources.map { |source_path|
33
+ # Behave like `ln` if the target is a directory; the file is made a direct
34
+ # descendent of that directory.
35
+ if target_is_dir
36
+ destination_path = File.join(destination, File.basename(source_path))
37
+ elsif destination
38
+ destination_path = destination
39
+ else
40
+ destination_path = source_path
41
+ end
42
+
43
+ options.merge(:source => source_path, :destination => destination_path)
44
+ }
45
+ end
46
+
47
+ def pretty_subject
48
+ "#{@destination.pretty} (#{@source.pretty})"
49
+ end
50
+
51
+ end