ngi 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +164 -0
  6. data/Rakefile +2 -0
  7. data/bin/ngi +35 -0
  8. data/lib/config/angular_init.config.json +100 -0
  9. data/lib/config/backup.angular_init.config.json +72 -0
  10. data/lib/dep/json.rb +62 -0
  11. data/lib/dep/json/add/bigdecimal.rb +28 -0
  12. data/lib/dep/json/add/complex.rb +28 -0
  13. data/lib/dep/json/add/core.rb +11 -0
  14. data/lib/dep/json/add/date.rb +34 -0
  15. data/lib/dep/json/add/date_time.rb +50 -0
  16. data/lib/dep/json/add/exception.rb +31 -0
  17. data/lib/dep/json/add/ostruct.rb +31 -0
  18. data/lib/dep/json/add/range.rb +29 -0
  19. data/lib/dep/json/add/rational.rb +27 -0
  20. data/lib/dep/json/add/regexp.rb +30 -0
  21. data/lib/dep/json/add/struct.rb +30 -0
  22. data/lib/dep/json/add/symbol.rb +25 -0
  23. data/lib/dep/json/add/time.rb +38 -0
  24. data/lib/dep/json/common.rb +484 -0
  25. data/lib/dep/json/ext.rb +21 -0
  26. data/lib/dep/json/ext/.keep +0 -0
  27. data/lib/dep/json/generic_object.rb +70 -0
  28. data/lib/dep/json/pure.rb +21 -0
  29. data/lib/dep/json/pure/generator.rb +522 -0
  30. data/lib/dep/json/pure/parser.rb +359 -0
  31. data/lib/dep/json/version.rb +8 -0
  32. data/lib/ngi.rb +16 -0
  33. data/lib/ngi/configure.rb +165 -0
  34. data/lib/ngi/delegate.rb +24 -0
  35. data/lib/ngi/generator.rb +199 -0
  36. data/lib/ngi/utils/command_parser.rb +104 -0
  37. data/lib/ngi/utils/jser.rb +46 -0
  38. data/lib/ngi/utils/utils.rb +30 -0
  39. data/lib/ngi/version.rb +3 -0
  40. data/lib/templates/markup/html/default/index.html +11 -0
  41. data/lib/templates/script/coffee/default/basic.js +23 -0
  42. data/lib/templates/script/coffee/default/config.js +12 -0
  43. data/lib/templates/script/coffee/default/constant.js +7 -0
  44. data/lib/templates/script/coffee/default/module.js +7 -0
  45. data/lib/templates/script/es5/default/basic.js +29 -0
  46. data/lib/templates/script/es5/default/config.js +13 -0
  47. data/lib/templates/script/es5/default/constant.js +7 -0
  48. data/lib/templates/script/es5/default/module.js +7 -0
  49. data/ngi.gemspec +23 -0
  50. metadata +129 -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.2'
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,16 @@
1
+ # angular_init (short-name: ngi)
2
+ # Copyright 2015 Joshua Beam
3
+ # github.com/joshbeam/angular_init
4
+ # MIT License
5
+
6
+ CURRENT_DIR = File.dirname(__FILE__)
7
+
8
+ require_relative "ngi/delegate"
9
+ require_relative "ngi/utils/utils"
10
+ require_relative "ngi/version"
11
+
12
+ module Ngi
13
+ # REVIEW: Is this the best way to do it?
14
+ Delegate = ::Delegate
15
+ UserInput = ::Utils::UserInput
16
+ end
@@ -0,0 +1,165 @@
1
+ # angular_init (short-name: ngi)
2
+ # Copyright 2015 Joshua Beam
3
+ # github.com/joshbeam/angular_init
4
+ # MIT License
5
+
6
+ # CURRENT_DIR is defined in angualr_init.rb
7
+
8
+ # require CURRENT_DIR+'/../../../lib/json'
9
+ # require CURRENT_DIR+'/../utils/utils'
10
+
11
+ require_relative '../dep/json'
12
+ require_relative 'utils/utils'
13
+
14
+ class Configure
15
+ attr_accessor :file, :location
16
+
17
+ Utils = ::Utils
18
+ JSArray = Utils::JSArray
19
+ JSHash = Utils::JSHash
20
+
21
+ # Make Questioner accesible as in: Configure::Questioner.run()
22
+ # "Questioner" simply starts an interactive prompt to guide
23
+ # the user in configuring src/config/agular_init.config.json,
24
+ # which is a JSON file that holds all the global configurable
25
+ # options (like language to use, templates, etc.)
26
+ class Questioner
27
+ attr_accessor :file
28
+
29
+ def initialize(file)
30
+ @file = file
31
+
32
+ @GLOBAL = @file['global']
33
+ # TODO: extend array with this inject function?
34
+
35
+ # The options for languages to use
36
+ @LANGUAGES = @GLOBAL['languages']
37
+
38
+ # The properties in key => value format of the properties the user can configure
39
+ @CONFIGURABLE = @GLOBAL['configurable']
40
+
41
+ # An array of the properties that the user is allowed to configure,
42
+ # according to src/config/angular_init.config.json
43
+ @CONFIGURABLE_PROPERTIES = @CONFIGURABLE.collect{ |k,v| v }
44
+
45
+ if block_given?
46
+ yield(self)
47
+ end
48
+ end
49
+
50
+ def choose_configurable_property
51
+ line_break = "\n------------------"
52
+
53
+ puts "\nCurrent settings #{line_break}"
54
+ @CONFIGURABLE.each_with_index do | (k,v),i |
55
+ puts "#{i+1}) "+v.capitalize+": "+JSHash.new(@GLOBAL[v]).to_str
56
+ end
57
+
58
+ # return
59
+ AskLoop.ask(:check => @CONFIGURABLE_PROPERTIES, :valid => JSArray.new(@CONFIGURABLE_PROPERTIES).to_str)
60
+ end
61
+
62
+ def configure_property(property)
63
+ case property
64
+ when @CONFIGURABLE['language']
65
+ language_types = @LANGUAGES.collect{|type,languages| type if languages.size > 1 }.reject{|t| t.nil?}
66
+
67
+ type = AskLoop.ask(:check => language_types, :valid => JSArray.new(language_types).to_str)
68
+
69
+ language_opts = @LANGUAGES.reject{|t,languages| languages if t != type}[type].reject{|l| l == @GLOBAL['language'][type]}
70
+
71
+ language = AskLoop.ask(:check => language_opts, :valid => JSArray.new(language_opts).to_str)
72
+
73
+ answer = @GLOBAL['language']
74
+
75
+ answer[type] = language
76
+ end
77
+
78
+ # TODO: add ability to add templates
79
+
80
+ answer
81
+ end
82
+
83
+
84
+ def self.run(file)
85
+ q = Questioner.new(file) do |q|
86
+ configurable_property = q.choose_configurable_property
87
+
88
+ result = q.configure_property(configurable_property)
89
+
90
+ q.file['global'][configurable_property] = result
91
+
92
+ puts configurable_property.capitalize+' set to: '+JSHash.new(result).to_str
93
+ end
94
+
95
+ q.file
96
+ end
97
+ end
98
+
99
+ # Here, we implement the virtual class "Utils::AskLoop"
100
+ # (see src/ruby/utils/utils.rb)
101
+ # This implementation just creates a loop that asks
102
+ # for user input
103
+ class AskLoop < Utils::AskLoop
104
+ def self.ask(args)
105
+ puts "\n"
106
+ puts 'Choose from: '+args[:valid]
107
+
108
+ answer = $stdin.gets.strip
109
+
110
+ while true
111
+ if args[:check].include?(answer)
112
+ break
113
+ else
114
+ puts 'Choose from: '+args[:valid]
115
+ puts '(or press ctrl+c to exit)'
116
+ answer = $stdin.gets.strip
117
+ end
118
+ end
119
+
120
+ answer
121
+ end
122
+ end
123
+
124
+ # The only thing we do here is load the JSON config file basically
125
+ # as just a string in JSON format.
126
+ # It will be converted to a Ruby hash in from_json below
127
+ def initialize
128
+ @location = CURRENT_DIR+'/config/angular_init.config.json'
129
+ @file = IO.read(@location)
130
+
131
+ if block_given?
132
+ yield(self)
133
+ end
134
+ end
135
+
136
+ # Convert the file to a Ruby hash
137
+ def from_json
138
+ JSON.parse(@file)
139
+ end
140
+
141
+ # Generate a "prettified" JSON version of our
142
+ # newly updated Ruby hash with the user's options
143
+ def to_json
144
+ JSON.pretty_generate(@file)
145
+ end
146
+
147
+ # Here we actually write the new JSON config file
148
+ # to src/config/angular_init.config.json
149
+ def write
150
+ new_file = to_json
151
+
152
+ File.open(@location,'w') do |f|
153
+ f.write(new_file)
154
+ f.close
155
+ end
156
+ end
157
+
158
+ def self.run
159
+ Configure.new do |c|
160
+ c.file = Configure::Questioner.run(c.from_json)
161
+
162
+ c.write
163
+ end
164
+ end
165
+ end