startapp 0.1.6

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.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/COPYRIGHT +1 -0
  3. data/LICENSE +11 -0
  4. data/README.md +95 -0
  5. data/Rakefile +6 -0
  6. data/autocomplete/rhc_bash +1672 -0
  7. data/bin/app +37 -0
  8. data/conf/express.conf +8 -0
  9. data/features/assets/deploy.tar.gz +0 -0
  10. data/features/core_feature.rb +191 -0
  11. data/features/deployments_feature.rb +129 -0
  12. data/features/domains_feature.rb +58 -0
  13. data/features/keys_feature.rb +37 -0
  14. data/features/members_feature.rb +166 -0
  15. data/lib/rhc/auth/basic.rb +64 -0
  16. data/lib/rhc/auth/token.rb +102 -0
  17. data/lib/rhc/auth/token_store.rb +53 -0
  18. data/lib/rhc/auth.rb +5 -0
  19. data/lib/rhc/autocomplete.rb +66 -0
  20. data/lib/rhc/autocomplete_templates/bash.erb +39 -0
  21. data/lib/rhc/cartridge_helpers.rb +118 -0
  22. data/lib/rhc/cli.rb +40 -0
  23. data/lib/rhc/command_runner.rb +185 -0
  24. data/lib/rhc/commands/account.rb +25 -0
  25. data/lib/rhc/commands/alias.rb +124 -0
  26. data/lib/rhc/commands/app.rb +726 -0
  27. data/lib/rhc/commands/apps.rb +20 -0
  28. data/lib/rhc/commands/authorization.rb +115 -0
  29. data/lib/rhc/commands/base.rb +174 -0
  30. data/lib/rhc/commands/cartridge.rb +329 -0
  31. data/lib/rhc/commands/clone.rb +66 -0
  32. data/lib/rhc/commands/configure.rb +20 -0
  33. data/lib/rhc/commands/create.rb +100 -0
  34. data/lib/rhc/commands/delete.rb +19 -0
  35. data/lib/rhc/commands/deploy.rb +32 -0
  36. data/lib/rhc/commands/deployment.rb +82 -0
  37. data/lib/rhc/commands/domain.rb +172 -0
  38. data/lib/rhc/commands/env.rb +142 -0
  39. data/lib/rhc/commands/force_stop.rb +17 -0
  40. data/lib/rhc/commands/git_clone.rb +34 -0
  41. data/lib/rhc/commands/logout.rb +51 -0
  42. data/lib/rhc/commands/logs.rb +21 -0
  43. data/lib/rhc/commands/member.rb +148 -0
  44. data/lib/rhc/commands/port_forward.rb +197 -0
  45. data/lib/rhc/commands/reload.rb +17 -0
  46. data/lib/rhc/commands/restart.rb +17 -0
  47. data/lib/rhc/commands/scp.rb +54 -0
  48. data/lib/rhc/commands/server.rb +40 -0
  49. data/lib/rhc/commands/setup.rb +60 -0
  50. data/lib/rhc/commands/show.rb +43 -0
  51. data/lib/rhc/commands/snapshot.rb +137 -0
  52. data/lib/rhc/commands/ssh.rb +51 -0
  53. data/lib/rhc/commands/sshkey.rb +97 -0
  54. data/lib/rhc/commands/start.rb +17 -0
  55. data/lib/rhc/commands/stop.rb +17 -0
  56. data/lib/rhc/commands/tail.rb +47 -0
  57. data/lib/rhc/commands/threaddump.rb +14 -0
  58. data/lib/rhc/commands/tidy.rb +17 -0
  59. data/lib/rhc/commands.rb +396 -0
  60. data/lib/rhc/config.rb +321 -0
  61. data/lib/rhc/context_helper.rb +121 -0
  62. data/lib/rhc/core_ext.rb +202 -0
  63. data/lib/rhc/coverage_helper.rb +33 -0
  64. data/lib/rhc/deployment_helpers.rb +111 -0
  65. data/lib/rhc/exceptions.rb +256 -0
  66. data/lib/rhc/git_helpers.rb +106 -0
  67. data/lib/rhc/help_formatter.rb +55 -0
  68. data/lib/rhc/helpers.rb +481 -0
  69. data/lib/rhc/highline_extensions.rb +479 -0
  70. data/lib/rhc/json.rb +51 -0
  71. data/lib/rhc/output_helpers.rb +260 -0
  72. data/lib/rhc/rest/activation.rb +11 -0
  73. data/lib/rhc/rest/alias.rb +42 -0
  74. data/lib/rhc/rest/api.rb +87 -0
  75. data/lib/rhc/rest/application.rb +348 -0
  76. data/lib/rhc/rest/attributes.rb +36 -0
  77. data/lib/rhc/rest/authorization.rb +8 -0
  78. data/lib/rhc/rest/base.rb +79 -0
  79. data/lib/rhc/rest/cartridge.rb +162 -0
  80. data/lib/rhc/rest/client.rb +650 -0
  81. data/lib/rhc/rest/deployment.rb +18 -0
  82. data/lib/rhc/rest/domain.rb +98 -0
  83. data/lib/rhc/rest/environment_variable.rb +15 -0
  84. data/lib/rhc/rest/gear_group.rb +16 -0
  85. data/lib/rhc/rest/httpclient.rb +145 -0
  86. data/lib/rhc/rest/key.rb +44 -0
  87. data/lib/rhc/rest/membership.rb +105 -0
  88. data/lib/rhc/rest/mock.rb +1042 -0
  89. data/lib/rhc/rest/user.rb +32 -0
  90. data/lib/rhc/rest.rb +148 -0
  91. data/lib/rhc/scp_helpers.rb +27 -0
  92. data/lib/rhc/ssh_helpers.rb +380 -0
  93. data/lib/rhc/tar_gz.rb +51 -0
  94. data/lib/rhc/usage_templates/command_help.erb +51 -0
  95. data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
  96. data/lib/rhc/usage_templates/help.erb +61 -0
  97. data/lib/rhc/usage_templates/missing_help.erb +1 -0
  98. data/lib/rhc/usage_templates/options_help.erb +12 -0
  99. data/lib/rhc/vendor/okjson.rb +600 -0
  100. data/lib/rhc/vendor/parseconfig.rb +178 -0
  101. data/lib/rhc/vendor/sshkey.rb +253 -0
  102. data/lib/rhc/vendor/zliby.rb +628 -0
  103. data/lib/rhc/version.rb +5 -0
  104. data/lib/rhc/wizard.rb +637 -0
  105. data/lib/rhc.rb +34 -0
  106. data/spec/coverage_helper.rb +82 -0
  107. data/spec/direct_execution_helper.rb +339 -0
  108. data/spec/keys/example.pem +23 -0
  109. data/spec/keys/example_private.pem +27 -0
  110. data/spec/keys/server.pem +19 -0
  111. data/spec/rest_spec_helper.rb +31 -0
  112. data/spec/rhc/assets/cert.crt +22 -0
  113. data/spec/rhc/assets/cert_key_rsa +27 -0
  114. data/spec/rhc/assets/empty.txt +0 -0
  115. data/spec/rhc/assets/env_vars.txt +7 -0
  116. data/spec/rhc/assets/env_vars_2.txt +1 -0
  117. data/spec/rhc/assets/foo.txt +1 -0
  118. data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
  119. data/spec/rhc/assets/targz_sample.tar.gz +0 -0
  120. data/spec/rhc/auth_spec.rb +442 -0
  121. data/spec/rhc/cli_spec.rb +186 -0
  122. data/spec/rhc/command_spec.rb +435 -0
  123. data/spec/rhc/commands/account_spec.rb +42 -0
  124. data/spec/rhc/commands/alias_spec.rb +333 -0
  125. data/spec/rhc/commands/app_spec.rb +777 -0
  126. data/spec/rhc/commands/apps_spec.rb +39 -0
  127. data/spec/rhc/commands/authorization_spec.rb +157 -0
  128. data/spec/rhc/commands/cartridge_spec.rb +665 -0
  129. data/spec/rhc/commands/clone_spec.rb +41 -0
  130. data/spec/rhc/commands/deployment_spec.rb +327 -0
  131. data/spec/rhc/commands/domain_spec.rb +401 -0
  132. data/spec/rhc/commands/env_spec.rb +493 -0
  133. data/spec/rhc/commands/git_clone_spec.rb +102 -0
  134. data/spec/rhc/commands/logout_spec.rb +86 -0
  135. data/spec/rhc/commands/member_spec.rb +247 -0
  136. data/spec/rhc/commands/port_forward_spec.rb +217 -0
  137. data/spec/rhc/commands/scp_spec.rb +77 -0
  138. data/spec/rhc/commands/server_spec.rb +69 -0
  139. data/spec/rhc/commands/setup_spec.rb +118 -0
  140. data/spec/rhc/commands/snapshot_spec.rb +179 -0
  141. data/spec/rhc/commands/ssh_spec.rb +163 -0
  142. data/spec/rhc/commands/sshkey_spec.rb +188 -0
  143. data/spec/rhc/commands/tail_spec.rb +81 -0
  144. data/spec/rhc/commands/threaddump_spec.rb +84 -0
  145. data/spec/rhc/config_spec.rb +407 -0
  146. data/spec/rhc/helpers_spec.rb +531 -0
  147. data/spec/rhc/highline_extensions_spec.rb +314 -0
  148. data/spec/rhc/json_spec.rb +30 -0
  149. data/spec/rhc/rest_application_spec.rb +258 -0
  150. data/spec/rhc/rest_client_spec.rb +752 -0
  151. data/spec/rhc/rest_spec.rb +740 -0
  152. data/spec/rhc/targz_spec.rb +55 -0
  153. data/spec/rhc/wizard_spec.rb +756 -0
  154. data/spec/spec_helper.rb +575 -0
  155. data/spec/wizard_spec_helper.rb +330 -0
  156. metadata +469 -0
@@ -0,0 +1,479 @@
1
+ require 'delegate'
2
+
3
+ #
4
+ # Add specific improved functionality
5
+ #
6
+ class HighLineExtension < HighLine
7
+ attr_writer :debug
8
+
9
+ [:ask, :agree].each do |sym|
10
+ define_method(sym) do |*args, &block|
11
+ separate_blocks
12
+ r = super(*args, &block)
13
+ @last_line_open = false
14
+ r
15
+ end
16
+ end
17
+
18
+ if HighLine::CHARACTER_MODE == 'stty'
19
+ def raw_no_echo_mode
20
+ @state = `stty -g 2>/dev/null`
21
+ `stty raw -echo -icanon isig 2>&1`
22
+ end
23
+
24
+ def restore_mode
25
+ `stty #{@state} 2>&1`
26
+ end
27
+ end
28
+
29
+ def debug(msg)
30
+ $stderr.puts "DEBUG: #{msg}" if debug?
31
+ end
32
+ def debug_error(e)
33
+ debug "#{e.message} (#{e.class})\n #{e.backtrace.join("\n ")}"
34
+ end
35
+ def debug?
36
+ @debug
37
+ end
38
+
39
+ # OVERRIDE
40
+ def say(msg)
41
+ if msg.respond_to? :to_str
42
+ separate_blocks
43
+
44
+ statement = msg.to_str
45
+ return statement unless statement.present?
46
+
47
+ template = ERB.new(statement, nil, "%")
48
+ statement = template.result(binding)
49
+
50
+ if @wrap_at
51
+ statement = statement.chomp.textwrap_ansi(@wrap_at, false)
52
+ if @last_line_open && statement.length > 1
53
+ @last_line_open = false
54
+ @output.puts
55
+ end
56
+ statement = statement.join("#{indentation}\n")
57
+ end
58
+ statement = send(:page_print, statement) unless @page_at.nil?
59
+
60
+ @output.print(indentation) unless @last_line_open
61
+
62
+ @last_line_open =
63
+ if statement[-1, 1] == " " or statement[-1, 1] == "\t"
64
+ @output.print(statement)
65
+ @output.flush
66
+ #statement.strip_ansi.length + (@last_line_open || 0)
67
+ true
68
+ else
69
+ @output.puts(statement)
70
+ false
71
+ end
72
+
73
+ elsif msg.respond_to? :each
74
+ separate_blocks
75
+
76
+ @output.print if @last_line_open
77
+ @last_line_open = false
78
+
79
+ color = msg.color if msg.respond_to? :color
80
+ @output.print HighLine::Style(color).code if color
81
+
82
+ msg.each do |s|
83
+ @output.print indentation
84
+ @output.puts s
85
+ end
86
+
87
+ @output.print HighLine::CLEAR if color
88
+ @output.flush
89
+ end
90
+
91
+ msg
92
+ end
93
+
94
+ # given an array of arrays "items", construct an array of strings that can
95
+ # be used to print in tabular form.
96
+ def table(items, opts={}, &block)
97
+ items = items.map(&block) if block_given?
98
+ opts[:width] ||= default_max_width
99
+ Table.new(items, opts)
100
+ end
101
+
102
+ def table_args(indent=nil, *args)
103
+ opts = {}
104
+ opts[:indent] = indent
105
+ opts[:width] = [default_max_width, *args]
106
+ opts
107
+ end
108
+
109
+ def default_max_width
110
+ @wrap_at ? @wrap_at - indentation.length : nil
111
+ end
112
+
113
+ def header(str,opts = {}, &block)
114
+ say Header.new(str, default_max_width, ' ')
115
+ if block_given?
116
+ indent &block
117
+ end
118
+ end
119
+
120
+ #:nocov:
121
+ # Backport from Highline 1.6.16
122
+ unless HighLine.method_defined? :indent
123
+ #
124
+ # Outputs indentation with current settings
125
+ #
126
+ def indentation
127
+ @indent_size ||= 2
128
+ @indent_level ||= 0
129
+ return ' '*@indent_size*@indent_level
130
+ end
131
+
132
+ #
133
+ # Executes block or outputs statement with indentation
134
+ #
135
+ def indent(increase=1, statement=nil, multiline=nil)
136
+ @indent_size ||= 2
137
+ @indent_level ||= 0
138
+ @indent_level += increase
139
+ multi = @multi_indent
140
+ @multi_indent = multiline unless multiline.nil?
141
+ if block_given?
142
+ yield self
143
+ else
144
+ say(statement)
145
+ end
146
+ ensure
147
+ @multi_indent = multi
148
+ @indent_level -= increase
149
+ end
150
+ end
151
+ #:nocov:
152
+
153
+ ##
154
+ # section
155
+ #
156
+ # highline helper mixin which correctly formats block of say and ask
157
+ # output to have correct margins. section remembers the last margin
158
+ # used and calculates the relitive margin from the previous section.
159
+ # For example:
160
+ #
161
+ # section(bottom=1) do
162
+ # say "Hello"
163
+ # end
164
+ #
165
+ # section(top=1) do
166
+ # say "World"
167
+ # end
168
+ #
169
+ # Will output:
170
+ #
171
+ # > Hello
172
+ # >
173
+ # > World
174
+ #
175
+ # with only one newline between the two. Biggest margin wins.
176
+ #
177
+ # params:
178
+ # top - top margin specified in lines
179
+ # bottom - bottom margin specified in line
180
+ #
181
+ def section(params={}, &block)
182
+ top = params[:top] || 0
183
+ bottom = params[:bottom] || 0
184
+
185
+ # the first section cannot take a newline
186
+ top = 0 unless @margin
187
+ @margin = [top, @margin || 0].max
188
+
189
+ separate_blocks if params[:now]
190
+ value = block.call
191
+
192
+ say "\n" if @last_line_open
193
+ @margin = [bottom, @margin].max
194
+
195
+ value
196
+ end
197
+
198
+ ##
199
+ # paragraph
200
+ #
201
+ # highline helper which creates a section with margins of 1, 1
202
+ #
203
+ def paragraph(&block)
204
+ section(:top => 1, :bottom => 1, &block)
205
+ end
206
+
207
+ def pager
208
+ #:nocov:
209
+ return if RHC::Helpers.windows?
210
+ return unless @output.tty?
211
+
212
+ read, write = IO.pipe
213
+
214
+ unless Kernel.fork
215
+ # Child process
216
+ STDOUT.reopen(write)
217
+ STDERR.reopen(write) if STDERR.tty?
218
+ read.close
219
+ write.close
220
+ return
221
+ end
222
+
223
+ # Parent process, become pager
224
+ STDIN.reopen(read)
225
+ read.close
226
+ write.close
227
+
228
+ ENV['LESS'] = 'FSRX' # Don't page if the input is short enough
229
+
230
+ Kernel.select [STDIN] # Wait until we have input before we start the pager
231
+ pager = ENV['PAGER'] || 'less'
232
+ exec pager rescue exec "/bin/sh", "-c", pager
233
+ #:nocov:
234
+ end
235
+
236
+ private
237
+ def separate_blocks
238
+ if (@margin ||= 0) > 0 && !@last_line_open
239
+ @output.print "\n" * @margin
240
+ @margin = 0
241
+ end
242
+ end
243
+ end
244
+
245
+ #
246
+ # An element capable of being split into multiple logical rows
247
+ #
248
+ module RowBased
249
+ extend Forwardable
250
+ def_delegators :rows, :each, :to_a, :join
251
+ alias_method :each_line, :each
252
+ end
253
+
254
+ class HighLine::Header < Struct.new(:text, :width, :indent, :color)
255
+ include RowBased
256
+
257
+ protected
258
+ def rows
259
+ @rows ||= begin
260
+ if !width || width == 0
261
+ [text.is_a?(Array) ? text.compact.join(' ') : text]
262
+
263
+ elsif text.is_a? Array
264
+ text.compact!
265
+ widths = text.map{ |s| s.strip_ansi.length }
266
+ chars, join, indented = 0, 1, (indent || '').length
267
+ narrow = width - indented
268
+ text.zip(widths).inject([]) do |rows, (section, w)|
269
+ if rows.empty?
270
+ if w > width
271
+ rows.concat(section.textwrap_ansi(width))
272
+ else
273
+ rows << section.dup
274
+ chars += w
275
+ end
276
+ else
277
+ if w + chars + join > narrow
278
+ rows.concat(section.textwrap_ansi(narrow).map{ |s| "#{indent}#{s}" })
279
+ chars = 0
280
+ elsif chars == 0
281
+ rows << "#{indent}#{section}"
282
+ chars += w + indented
283
+ else
284
+ rows[-1] << " #{section}"
285
+ chars += w + join
286
+ end
287
+ end
288
+ rows
289
+ end
290
+ else
291
+ text.textwrap_ansi(width)
292
+ end
293
+ end.tap do |rows|
294
+ rows << '-' * (rows.map{ |s| s.strip_ansi.length }.max || 0)
295
+ end
296
+ end
297
+ end
298
+
299
+ #
300
+ # Represent a columnar layout of items with wrapping and flexible layout.
301
+ #
302
+ class HighLine::Table
303
+ include RowBased
304
+
305
+ def initialize(items=nil,options={},&mapper)
306
+ @items, @options, @mapper = items, options, mapper
307
+ end
308
+
309
+ def color
310
+ opts[:color]
311
+ end
312
+
313
+ protected
314
+ attr_reader :items
315
+
316
+ def opts
317
+ @options
318
+ end
319
+
320
+ def align
321
+ opts[:align] || []
322
+ end
323
+ def joiner
324
+ opts[:join] || ' '
325
+ end
326
+ def indent
327
+ opts[:indent] || ''
328
+ end
329
+ def heading
330
+ @heading ||= opts[:heading] ? HighLine::Header.new(opts[:heading], max_width, indent) : nil
331
+ end
332
+
333
+ def source_rows
334
+ @source_rows ||= begin
335
+ (@mapper ? (items.map &@mapper) : items).each do |row|
336
+ row.map! do |col|
337
+ case col
338
+ when Array then col.join("\n")
339
+ when String then col
340
+ else col.to_s
341
+ end
342
+ end
343
+ end
344
+ end
345
+ end
346
+
347
+ def headers
348
+ @headers ||= opts[:header] ? [Array(opts[:header])] : []
349
+ end
350
+
351
+ def columns
352
+ @columns ||= source_rows.map(&:length).max || 0
353
+ end
354
+
355
+ def column_widths
356
+ @column_widths ||= begin
357
+ widths = Array.new(columns){ Width.new(0,0,0) }
358
+ (source_rows + headers).each do |row|
359
+ row.each_with_index do |col, i|
360
+ w = widths[i]
361
+ s = col.strip_ansi
362
+ word_length = s.scan(/\b\S+/).inject(0){ |l, word| l = word.length if l <= word.length; l }
363
+ w.min = word_length unless w.min > word_length
364
+ w.max = s.length unless w.max > s.length
365
+ end
366
+ end
367
+ widths
368
+ end
369
+ end
370
+
371
+ Width = Struct.new(:min, :max, :set)
372
+
373
+ def allocate_widths_for(available)
374
+ available -= (columns-1) * joiner.length + indent.length
375
+ return column_widths.map{ |w| w.max } if available >= column_widths.inject(0){ |sum, w| sum + w.max } || column_widths.inject(0){ |sum, w| sum + w.min } > available
376
+
377
+ fair = available / columns
378
+ column_widths.each do |w|
379
+ if w.set > 0
380
+ available -= w.set
381
+ next
382
+ end
383
+ w.set = if w.max <= fair
384
+ available -= w.max
385
+ w.max
386
+ else
387
+ 0
388
+ end
389
+ end
390
+
391
+ remaining = column_widths.inject(0) do |sum, w|
392
+ if w.set == 0
393
+ sum += w.max
394
+ available -= w.min
395
+ end
396
+ sum
397
+ end
398
+ fair = available.to_f / remaining.to_f
399
+
400
+ column_widths.
401
+ each do |w|
402
+ if w.set == 0
403
+ alloc = (w.max * fair).to_i
404
+ overflow = alloc + w.min - w.max
405
+ if overflow > 0
406
+ alloc -= overflow
407
+ end
408
+ available -= alloc
409
+ w.set = alloc + w.min
410
+ end
411
+ end.
412
+ each do |w|
413
+ next unless available > 0
414
+ gap = w.max - w.set
415
+ if gap > 0
416
+ left = [gap,available].min
417
+ available -= left
418
+ w.set += left
419
+ end
420
+ end.map(&:set)
421
+ end
422
+
423
+ def widths
424
+ @widths ||= begin
425
+ case w = opts[:width]
426
+ when Array
427
+ column_widths.zip(w[1..-1]).each do |width, col|
428
+ width.set = col || 0
429
+ width.max = width.set if width.set > width.max
430
+ end
431
+ allocate_widths_for(w.first || 0)
432
+ when Integer
433
+ allocate_widths_for(w)
434
+ else
435
+ column_widths.map{ |w| w.max }
436
+ end
437
+ end
438
+ end
439
+
440
+ def max_width
441
+ @max_width ||= opts[:width].is_a?(Array) ? opts[:width].first : (opts[:width] ? opts[:width] : 0)
442
+ end
443
+
444
+ def header_rows
445
+ @header_rows ||= begin
446
+ headers << widths.map{ |w| '-' * w } if headers.present?
447
+ headers
448
+ end
449
+ end
450
+
451
+ def rows
452
+ @rows ||= begin
453
+ body = (header_rows + source_rows).inject([]) do |a,row|
454
+ row = row.zip(widths).map{ |column,w| w && w > 0 ? column.textwrap_ansi(w, false) : [column] }
455
+ (row.map(&:length).max || 0).times do |i|
456
+ s = []
457
+ row.each_with_index do |lines, j|
458
+ cell = lines[i]
459
+ l = cell ? cell.strip_ansi.length : 0
460
+ s <<
461
+ if align[j] == :right
462
+ "#{' '*(widths[j]-l) if l < widths[j]}#{cell}"
463
+ else
464
+ "#{cell}#{' '*(widths[j]-l) if l < widths[j]}"
465
+ end
466
+ end
467
+ a << "#{indent}#{s.join(joiner).rstrip}"
468
+ end
469
+ a
470
+ end
471
+
472
+ body = heading.to_a.concat(body) if heading
473
+ body
474
+ end
475
+ end
476
+ end
477
+
478
+ $terminal = HighLineExtension.new
479
+ $terminal.indent_size = 2 if $terminal.respond_to? :indent_size
data/lib/rhc/json.rb ADDED
@@ -0,0 +1,51 @@
1
+ require 'rhc/vendor/okjson'
2
+
3
+ module RHC
4
+
5
+ module Json
6
+
7
+ def self.decode(string, options={})
8
+ string = string.read if string.respond_to?(:read)
9
+ result = RHC::Vendor::OkJson.decode(string)
10
+ options[:symbolize_keys] ? symbolize_keys(result) : result
11
+ end
12
+
13
+ def self.encode(object, options={})
14
+ RHC::Vendor::OkJson.valenc(stringify_keys(object))
15
+ end
16
+
17
+ def self.symbolize_keys(object)
18
+ modify_keys(object) do |key|
19
+ key.is_a?(String) ? key.to_sym : key
20
+ end
21
+ end
22
+
23
+ def self.stringify_keys(object)
24
+ modify_keys(object) do |key|
25
+ key.is_a?(Symbol) ? key.to_s : key
26
+ end
27
+ end
28
+
29
+ def self.modify_keys(object, &modifier)
30
+ case object
31
+ when Array
32
+ object.map do |value|
33
+ modify_keys(value, &modifier)
34
+ end
35
+ when Hash
36
+ object.inject({}) do |result, (key, value)|
37
+ new_key = modifier.call(key)
38
+ new_value = modify_keys(value, &modifier)
39
+ result.merge! new_key => new_value
40
+ end
41
+ else
42
+ object
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ class JsonError < ::StandardError; end
49
+
50
+ end
51
+