gist 4.6.2 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/spec/rawify_spec.rb CHANGED
@@ -6,7 +6,16 @@ describe '...' do
6
6
  end
7
7
 
8
8
  it "should return the raw file url" do
9
- Gist.gist("Test gist", :output => :raw_url, :anonymous => true).should == "https://gist.github.com/anonymous/XXXXXX/raw"
9
+ Gist.gist("Test gist", :output => :raw_url, :anonymous => false).should == "https://gist.github.com/anonymous/XXXXXX/raw"
10
+ end
11
+
12
+ it 'should raise an error when trying to do operations without being logged in' do
13
+ error_msg = 'Anonymous gists are no longer supported. Please log in with `gist --login`. ' \
14
+ '(GitHub now requires credentials to gist https://bit.ly/2GBBxKw)'
15
+
16
+ expect do
17
+ Gist.gist("Test gist", output: :raw_url, anonymous: true)
18
+ end.to raise_error(StandardError, error_msg)
10
19
  end
11
20
  end
12
21
 
data/spec/shorten_spec.rb CHANGED
@@ -5,11 +5,20 @@ describe '...' do
5
5
 
6
6
  it "should return a shortened version of the URL when response is 200" do
7
7
  stub_request(:post, "https://git.io/create").to_return(:status => 200, :body => 'XXXXXX')
8
- Gist.gist("Test gist", :output => :short_url, :anonymous => true).should == "https://git.io/XXXXXX"
8
+ Gist.gist("Test gist", :output => :short_url, anonymous: false).should == "https://git.io/XXXXXX"
9
9
  end
10
10
 
11
11
  it "should return a shortened version of the URL when response is 201" do
12
12
  stub_request(:post, "https://git.io/create").to_return(:status => 201, :headers => { 'Location' => 'https://git.io/XXXXXX' })
13
- Gist.gist("Test gist", :output => :short_url, :anonymous => true).should == "https://git.io/XXXXXX"
13
+ Gist.gist("Test gist", :output => :short_url, anonymous: false).should == "https://git.io/XXXXXX"
14
+ end
15
+
16
+ it 'should raise an error when trying to get short urls without being logged in' do
17
+ error_msg = 'Anonymous gists are no longer supported. Please log in with `gist --login`. ' \
18
+ '(GitHub now requires credentials to gist https://bit.ly/2GBBxKw)'
19
+
20
+ expect do
21
+ Gist.gist("Test gist", output: :short_url, anonymous: true)
22
+ end.to raise_error(StandardError, error_msg)
14
23
  end
15
24
  end
data/spec/spec_helper.rb CHANGED
@@ -11,7 +11,7 @@ RSpec.configure do |config|
11
11
  mocks.syntax = :should
12
12
  end
13
13
  config.expect_with :rspec do |expectations|
14
- expectations.syntax = :should
14
+ expectations.syntax = [:should, :expect]
15
15
  end
16
16
  end
17
17
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gist
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.6.2
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Conrad Irwin
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-01-09 00:00:00.000000000 Z
12
+ date: 2020-08-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -76,15 +76,12 @@ executables:
76
76
  extensions: []
77
77
  extra_rdoc_files: []
78
78
  files:
79
- - ".gitignore"
80
79
  - ".rspec"
81
80
  - Gemfile
82
81
  - LICENSE.MIT
83
82
  - README.md
84
83
  - Rakefile
85
84
  - bin/gist
86
- - build/gist
87
- - build/gist.1
88
85
  - gist.gemspec
89
86
  - lib/gist.rb
90
87
  - spec/auth_token_file_spec.rb
@@ -115,8 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
112
  - !ruby/object:Gem::Version
116
113
  version: '0'
117
114
  requirements: []
118
- rubyforge_project:
119
- rubygems_version: 2.6.11
115
+ rubygems_version: 3.0.3
120
116
  signing_key:
121
117
  specification_version: 4
122
118
  summary: Just allows you to upload gists
data/.gitignore DELETED
@@ -1,8 +0,0 @@
1
- .rvmrc
2
- Gemfile.lock
3
-
4
- # OS X
5
- .DS_Store
6
- .yardoc
7
- doc
8
- *.gem
data/build/gist DELETED
@@ -1,2092 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # This is generated from https://github.com/defunkt/gist using 'rake standalone'
3
- # any changes will be overwritten.
4
- require 'net/https'
5
- require 'cgi'
6
- require 'uri'
7
-
8
- begin
9
- require 'strscan'
10
-
11
- module JSON
12
- module Pure
13
- # This class implements the JSON parser that is used to parse a JSON string
14
- # into a Ruby data structure.
15
- class Parser < StringScanner
16
- STRING = /" ((?:[^\x0-\x1f"\\] |
17
- # escaped special characters:
18
- \\["\\\/bfnrt] |
19
- \\u[0-9a-fA-F]{4} |
20
- # match all but escaped special characters:
21
- \\[\x20-\x21\x23-\x2e\x30-\x5b\x5d-\x61\x63-\x65\x67-\x6d\x6f-\x71\x73\x75-\xff])*)
22
- "/nx
23
- INTEGER = /(-?0|-?[1-9]\d*)/
24
- FLOAT = /(-?
25
- (?:0|[1-9]\d*)
26
- (?:
27
- \.\d+(?i:e[+-]?\d+) |
28
- \.\d+ |
29
- (?i:e[+-]?\d+)
30
- )
31
- )/x
32
- NAN = /NaN/
33
- INFINITY = /Infinity/
34
- MINUS_INFINITY = /-Infinity/
35
- OBJECT_OPEN = /\{/
36
- OBJECT_CLOSE = /\}/
37
- ARRAY_OPEN = /\[/
38
- ARRAY_CLOSE = /\]/
39
- PAIR_DELIMITER = /:/
40
- COLLECTION_DELIMITER = /,/
41
- TRUE = /true/
42
- FALSE = /false/
43
- NULL = /null/
44
- IGNORE = %r(
45
- (?:
46
- //[^\n\r]*[\n\r]| # line comments
47
- /\* # c-style comments
48
- (?:
49
- [^*/]| # normal chars
50
- /[^*]| # slashes that do not start a nested comment
51
- \*[^/]| # asterisks that do not end this comment
52
- /(?=\*/) # single slash before this comment's end
53
- )*
54
- \*/ # the End of this comment
55
- |[ \t\r\n]+ # whitespaces: space, horicontal tab, lf, cr
56
- )+
57
- )mx
58
-
59
- UNPARSED = Object.new
60
-
61
- # Creates a new JSON::Pure::Parser instance for the string _source_.
62
- #
63
- # It will be configured by the _opts_ hash. _opts_ can have the following
64
- # keys:
65
- # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
66
- # structures. Disable depth checking with :max_nesting => false|nil|0,
67
- # it defaults to 19.
68
- # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
69
- # defiance of RFC 4627 to be parsed by the Parser. This option defaults
70
- # to false.
71
- # * *symbolize_names*: If set to true, returns symbols for the names
72
- # (keys) in a JSON object. Otherwise strings are returned, which is also
73
- # the default.
74
- # * *create_additions*: If set to false, the Parser doesn't create
75
- # additions even if a matchin class and create_id was found. This option
76
- # defaults to true.
77
- # * *object_class*: Defaults to Hash
78
- # * *array_class*: Defaults to Array
79
- # * *quirks_mode*: Enables quirks_mode for parser, that is for example
80
- # parsing single JSON values instead of documents is possible.
81
- def initialize(source, opts = {})
82
- opts ||= {}
83
- unless @quirks_mode = opts[:quirks_mode]
84
- source = convert_encoding source
85
- end
86
- super source
87
- if !opts.key?(:max_nesting) # defaults to 19
88
- @max_nesting = 19
89
- elsif opts[:max_nesting]
90
- @max_nesting = opts[:max_nesting]
91
- else
92
- @max_nesting = 0
93
- end
94
- @allow_nan = !!opts[:allow_nan]
95
- @symbolize_names = !!opts[:symbolize_names]
96
- if opts.key?(:create_additions)
97
- @create_additions = !!opts[:create_additions]
98
- else
99
- @create_additions = true
100
- end
101
- @create_id = @create_additions ? JSON.create_id : nil
102
- @object_class = opts[:object_class] || Hash
103
- @array_class = opts[:array_class] || Array
104
- @match_string = opts[:match_string]
105
- end
106
-
107
- alias source string
108
-
109
- def quirks_mode?
110
- !!@quirks_mode
111
- end
112
-
113
- def reset
114
- super
115
- @current_nesting = 0
116
- end
117
-
118
- # Parses the current JSON string _source_ and returns the complete data
119
- # structure as a result.
120
- def parse
121
- reset
122
- obj = nil
123
- if @quirks_mode
124
- while !eos? && skip(IGNORE)
125
- end
126
- if eos?
127
- raise ParserError, "source did not contain any JSON!"
128
- else
129
- obj = parse_value
130
- obj == UNPARSED and raise ParserError, "source did not contain any JSON!"
131
- end
132
- else
133
- until eos?
134
- case
135
- when scan(OBJECT_OPEN)
136
- obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
137
- @current_nesting = 1
138
- obj = parse_object
139
- when scan(ARRAY_OPEN)
140
- obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
141
- @current_nesting = 1
142
- obj = parse_array
143
- when skip(IGNORE)
144
- ;
145
- else
146
- raise ParserError, "source '#{peek(20)}' not in JSON!"
147
- end
148
- end
149
- obj or raise ParserError, "source did not contain any JSON!"
150
- end
151
- obj
152
- end
153
-
154
- private
155
-
156
- def convert_encoding(source)
157
- if source.respond_to?(:to_str)
158
- source = source.to_str
159
- else
160
- raise TypeError, "#{source.inspect} is not like a string"
161
- end
162
- if defined?(::Encoding)
163
- if source.encoding == ::Encoding::ASCII_8BIT
164
- b = source[0, 4].bytes.to_a
165
- source =
166
- case
167
- when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
168
- source.dup.force_encoding(::Encoding::UTF_32BE).encode!(::Encoding::UTF_8)
169
- when b.size >= 4 && b[0] == 0 && b[2] == 0
170
- source.dup.force_encoding(::Encoding::UTF_16BE).encode!(::Encoding::UTF_8)
171
- when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
172
- source.dup.force_encoding(::Encoding::UTF_32LE).encode!(::Encoding::UTF_8)
173
- when b.size >= 4 && b[1] == 0 && b[3] == 0
174
- source.dup.force_encoding(::Encoding::UTF_16LE).encode!(::Encoding::UTF_8)
175
- else
176
- source.dup
177
- end
178
- else
179
- source = source.encode(::Encoding::UTF_8)
180
- end
181
- source.force_encoding(::Encoding::ASCII_8BIT)
182
- else
183
- b = source
184
- source =
185
- case
186
- when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
187
- JSON.iconv('utf-8', 'utf-32be', b)
188
- when b.size >= 4 && b[0] == 0 && b[2] == 0
189
- JSON.iconv('utf-8', 'utf-16be', b)
190
- when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
191
- JSON.iconv('utf-8', 'utf-32le', b)
192
- when b.size >= 4 && b[1] == 0 && b[3] == 0
193
- JSON.iconv('utf-8', 'utf-16le', b)
194
- else
195
- b
196
- end
197
- end
198
- source
199
- end
200
-
201
- # Unescape characters in strings.
202
- UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
203
- UNESCAPE_MAP.update({
204
- ?" => '"',
205
- ?\\ => '\\',
206
- ?/ => '/',
207
- ?b => "\b",
208
- ?f => "\f",
209
- ?n => "\n",
210
- ?r => "\r",
211
- ?t => "\t",
212
- ?u => nil,
213
- })
214
-
215
- EMPTY_8BIT_STRING = ''
216
- if ::String.method_defined?(:encode)
217
- EMPTY_8BIT_STRING.force_encoding Encoding::ASCII_8BIT
218
- end
219
-
220
- def parse_string
221
- if scan(STRING)
222
- return '' if self[1].empty?
223
- string = self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
224
- if u = UNESCAPE_MAP[$&[1]]
225
- u
226
- else # \uXXXX
227
- bytes = EMPTY_8BIT_STRING.dup
228
- i = 0
229
- while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
230
- bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
231
- i += 1
232
- end
233
- JSON.iconv('utf-8', 'utf-16be', bytes)
234
- end
235
- end
236
- if string.respond_to?(:force_encoding)
237
- string.force_encoding(::Encoding::UTF_8)
238
- end
239
- if @create_additions and @match_string
240
- for (regexp, klass) in @match_string
241
- klass.json_creatable? or next
242
- string =~ regexp and return klass.json_create(string)
243
- end
244
- end
245
- string
246
- else
247
- UNPARSED
248
- end
249
- rescue => e
250
- raise ParserError, "Caught #{e.class} at '#{peek(20)}': #{e}"
251
- end
252
-
253
- def parse_value
254
- case
255
- when scan(FLOAT)
256
- Float(self[1])
257
- when scan(INTEGER)
258
- Integer(self[1])
259
- when scan(TRUE)
260
- true
261
- when scan(FALSE)
262
- false
263
- when scan(NULL)
264
- nil
265
- when (string = parse_string) != UNPARSED
266
- string
267
- when scan(ARRAY_OPEN)
268
- @current_nesting += 1
269
- ary = parse_array
270
- @current_nesting -= 1
271
- ary
272
- when scan(OBJECT_OPEN)
273
- @current_nesting += 1
274
- obj = parse_object
275
- @current_nesting -= 1
276
- obj
277
- when @allow_nan && scan(NAN)
278
- NaN
279
- when @allow_nan && scan(INFINITY)
280
- Infinity
281
- when @allow_nan && scan(MINUS_INFINITY)
282
- MinusInfinity
283
- else
284
- UNPARSED
285
- end
286
- end
287
-
288
- def parse_array
289
- raise NestingError, "nesting of #@current_nesting is too deep" if
290
- @max_nesting.nonzero? && @current_nesting > @max_nesting
291
- result = @array_class.new
292
- delim = false
293
- until eos?
294
- case
295
- when (value = parse_value) != UNPARSED
296
- delim = false
297
- result << value
298
- skip(IGNORE)
299
- if scan(COLLECTION_DELIMITER)
300
- delim = true
301
- elsif match?(ARRAY_CLOSE)
302
- ;
303
- else
304
- raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
305
- end
306
- when scan(ARRAY_CLOSE)
307
- if delim
308
- raise ParserError, "expected next element in array at '#{peek(20)}'!"
309
- end
310
- break
311
- when skip(IGNORE)
312
- ;
313
- else
314
- raise ParserError, "unexpected token in array at '#{peek(20)}'!"
315
- end
316
- end
317
- result
318
- end
319
-
320
- def parse_object
321
- raise NestingError, "nesting of #@current_nesting is too deep" if
322
- @max_nesting.nonzero? && @current_nesting > @max_nesting
323
- result = @object_class.new
324
- delim = false
325
- until eos?
326
- case
327
- when (string = parse_string) != UNPARSED
328
- skip(IGNORE)
329
- unless scan(PAIR_DELIMITER)
330
- raise ParserError, "expected ':' in object at '#{peek(20)}'!"
331
- end
332
- skip(IGNORE)
333
- unless (value = parse_value).equal? UNPARSED
334
- result[@symbolize_names ? string.to_sym : string] = value
335
- delim = false
336
- skip(IGNORE)
337
- if scan(COLLECTION_DELIMITER)
338
- delim = true
339
- elsif match?(OBJECT_CLOSE)
340
- ;
341
- else
342
- raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!"
343
- end
344
- else
345
- raise ParserError, "expected value in object at '#{peek(20)}'!"
346
- end
347
- when scan(OBJECT_CLOSE)
348
- if delim
349
- raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!"
350
- end
351
- if @create_additions and klassname = result[@create_id]
352
- klass = JSON.deep_const_get klassname
353
- break unless klass and klass.json_creatable?
354
- result = klass.json_create(result)
355
- end
356
- break
357
- when skip(IGNORE)
358
- ;
359
- else
360
- raise ParserError, "unexpected token in object at '#{peek(20)}'!"
361
- end
362
- end
363
- result
364
- end
365
- end
366
- end
367
- end
368
-
369
- module JSON
370
- MAP = {
371
- "\x0" => '\u0000',
372
- "\x1" => '\u0001',
373
- "\x2" => '\u0002',
374
- "\x3" => '\u0003',
375
- "\x4" => '\u0004',
376
- "\x5" => '\u0005',
377
- "\x6" => '\u0006',
378
- "\x7" => '\u0007',
379
- "\b" => '\b',
380
- "\t" => '\t',
381
- "\n" => '\n',
382
- "\xb" => '\u000b',
383
- "\f" => '\f',
384
- "\r" => '\r',
385
- "\xe" => '\u000e',
386
- "\xf" => '\u000f',
387
- "\x10" => '\u0010',
388
- "\x11" => '\u0011',
389
- "\x12" => '\u0012',
390
- "\x13" => '\u0013',
391
- "\x14" => '\u0014',
392
- "\x15" => '\u0015',
393
- "\x16" => '\u0016',
394
- "\x17" => '\u0017',
395
- "\x18" => '\u0018',
396
- "\x19" => '\u0019',
397
- "\x1a" => '\u001a',
398
- "\x1b" => '\u001b',
399
- "\x1c" => '\u001c',
400
- "\x1d" => '\u001d',
401
- "\x1e" => '\u001e',
402
- "\x1f" => '\u001f',
403
- '"' => '\"',
404
- '\\' => '\\\\',
405
- } # :nodoc:
406
-
407
- # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
408
- # UTF16 big endian characters as \u????, and return it.
409
- if defined?(::Encoding)
410
- def utf8_to_json(string) # :nodoc:
411
- string = string.dup
412
- string << '' # XXX workaround: avoid buffer sharing
413
- string.force_encoding(::Encoding::ASCII_8BIT)
414
- string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] }
415
- string.force_encoding(::Encoding::UTF_8)
416
- string
417
- end
418
-
419
- def utf8_to_json_ascii(string) # :nodoc:
420
- string = string.dup
421
- string << '' # XXX workaround: avoid buffer sharing
422
- string.force_encoding(::Encoding::ASCII_8BIT)
423
- string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] }
424
- string.gsub!(/(
425
- (?:
426
- [\xc2-\xdf][\x80-\xbf] |
427
- [\xe0-\xef][\x80-\xbf]{2} |
428
- [\xf0-\xf4][\x80-\xbf]{3}
429
- )+ |
430
- [\x80-\xc1\xf5-\xff] # invalid
431
- )/nx) { |c|
432
- c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
433
- s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
434
- s.gsub!(/.{4}/n, '\\\\u\&')
435
- }
436
- string.force_encoding(::Encoding::UTF_8)
437
- string
438
- rescue => e
439
- raise GeneratorError, "Caught #{e.class}: #{e}"
440
- end
441
- else
442
- def utf8_to_json(string) # :nodoc:
443
- string.gsub(/["\\\x0-\x1f]/) { MAP[$&] }
444
- end
445
-
446
- def utf8_to_json_ascii(string) # :nodoc:
447
- string = string.gsub(/["\\\x0-\x1f]/) { MAP[$&] }
448
- string.gsub!(/(
449
- (?:
450
- [\xc2-\xdf][\x80-\xbf] |
451
- [\xe0-\xef][\x80-\xbf]{2} |
452
- [\xf0-\xf4][\x80-\xbf]{3}
453
- )+ |
454
- [\x80-\xc1\xf5-\xff] # invalid
455
- )/nx) { |c|
456
- c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
457
- s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
458
- s.gsub!(/.{4}/n, '\\\\u\&')
459
- }
460
- string
461
- rescue => e
462
- raise GeneratorError, "Caught #{e.class}: #{e}"
463
- end
464
- end
465
- module_function :utf8_to_json, :utf8_to_json_ascii
466
-
467
- module Pure
468
- module Generator
469
- # This class is used to create State instances, that are use to hold data
470
- # while generating a JSON text from a Ruby data structure.
471
- class State
472
- # Creates a State object from _opts_, which ought to be Hash to create
473
- # a new State instance configured by _opts_, something else to create
474
- # an unconfigured instance. If _opts_ is a State object, it is just
475
- # returned.
476
- def self.from_state(opts)
477
- case
478
- when self === opts
479
- opts
480
- when opts.respond_to?(:to_hash)
481
- new(opts.to_hash)
482
- when opts.respond_to?(:to_h)
483
- new(opts.to_h)
484
- else
485
- SAFE_STATE_PROTOTYPE.dup
486
- end
487
- end
488
-
489
- # Instantiates a new State object, configured by _opts_.
490
- #
491
- # _opts_ can have the following keys:
492
- #
493
- # * *indent*: a string used to indent levels (default: ''),
494
- # * *space*: a string that is put after, a : or , delimiter (default: ''),
495
- # * *space_before*: a string that is put before a : pair delimiter (default: ''),
496
- # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
497
- # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
498
- # * *check_circular*: is deprecated now, use the :max_nesting option instead,
499
- # * *max_nesting*: sets the maximum level of data structure nesting in
500
- # the generated JSON, max_nesting = 0 if no maximum should be checked.
501
- # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
502
- # generated, otherwise an exception is thrown, if these values are
503
- # encountered. This options defaults to false.
504
- # * *quirks_mode*: Enables quirks_mode for parser, that is for example
505
- # generating single JSON values instead of documents is possible.
506
- def initialize(opts = {})
507
- @indent = ''
508
- @space = ''
509
- @space_before = ''
510
- @object_nl = ''
511
- @array_nl = ''
512
- @allow_nan = false
513
- @ascii_only = false
514
- @quirks_mode = false
515
- @buffer_initial_length = 1024
516
- configure opts
517
- end
518
-
519
- # This string is used to indent levels in the JSON text.
520
- attr_accessor :indent
521
-
522
- # This string is used to insert a space between the tokens in a JSON
523
- # string.
524
- attr_accessor :space
525
-
526
- # This string is used to insert a space before the ':' in JSON objects.
527
- attr_accessor :space_before
528
-
529
- # This string is put at the end of a line that holds a JSON object (or
530
- # Hash).
531
- attr_accessor :object_nl
532
-
533
- # This string is put at the end of a line that holds a JSON array.
534
- attr_accessor :array_nl
535
-
536
- # This integer returns the maximum level of data structure nesting in
537
- # the generated JSON, max_nesting = 0 if no maximum is checked.
538
- attr_accessor :max_nesting
539
-
540
- # If this attribute is set to true, quirks mode is enabled, otherwise
541
- # it's disabled.
542
- attr_accessor :quirks_mode
543
-
544
- # :stopdoc:
545
- attr_reader :buffer_initial_length
546
-
547
- def buffer_initial_length=(length)
548
- if length > 0
549
- @buffer_initial_length = length
550
- end
551
- end
552
- # :startdoc:
553
-
554
- # This integer returns the current depth data structure nesting in the
555
- # generated JSON.
556
- attr_accessor :depth
557
-
558
- def check_max_nesting # :nodoc:
559
- return if @max_nesting.zero?
560
- current_nesting = depth + 1
561
- current_nesting > @max_nesting and
562
- raise NestingError, "nesting of #{current_nesting} is too deep"
563
- end
564
-
565
- # Returns true, if circular data structures are checked,
566
- # otherwise returns false.
567
- def check_circular?
568
- !@max_nesting.zero?
569
- end
570
-
571
- # Returns true if NaN, Infinity, and -Infinity should be considered as
572
- # valid JSON and output.
573
- def allow_nan?
574
- @allow_nan
575
- end
576
-
577
- # Returns true, if only ASCII characters should be generated. Otherwise
578
- # returns false.
579
- def ascii_only?
580
- @ascii_only
581
- end
582
-
583
- # Returns true, if quirks mode is enabled. Otherwise returns false.
584
- def quirks_mode?
585
- @quirks_mode
586
- end
587
-
588
- # Configure this State instance with the Hash _opts_, and return
589
- # itself.
590
- def configure(opts)
591
- @indent = opts[:indent] if opts.key?(:indent)
592
- @space = opts[:space] if opts.key?(:space)
593
- @space_before = opts[:space_before] if opts.key?(:space_before)
594
- @object_nl = opts[:object_nl] if opts.key?(:object_nl)
595
- @array_nl = opts[:array_nl] if opts.key?(:array_nl)
596
- @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
597
- @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
598
- @depth = opts[:depth] || 0
599
- @quirks_mode = opts[:quirks_mode] if opts.key?(:quirks_mode)
600
- if !opts.key?(:max_nesting) # defaults to 19
601
- @max_nesting = 19
602
- elsif opts[:max_nesting]
603
- @max_nesting = opts[:max_nesting]
604
- else
605
- @max_nesting = 0
606
- end
607
- self
608
- end
609
- alias merge configure
610
-
611
- # Returns the configuration instance variables as a hash, that can be
612
- # passed to the configure method.
613
- def to_h
614
- result = {}
615
- for iv in %w[indent space space_before object_nl array_nl allow_nan max_nesting ascii_only quirks_mode buffer_initial_length depth]
616
- result[iv.intern] = instance_variable_get("@#{iv}")
617
- end
618
- result
619
- end
620
-
621
- # Generates a valid JSON document from object +obj+ and returns the
622
- # result. If no valid JSON document can be created this method raises a
623
- # GeneratorError exception.
624
- def generate(obj)
625
- result = obj.to_json(self)
626
- unless @quirks_mode
627
- unless result =~ /\A\s*\[/ && result =~ /\]\s*\Z/ ||
628
- result =~ /\A\s*\{/ && result =~ /\}\s*\Z/
629
- then
630
- raise GeneratorError, "only generation of JSON objects or arrays allowed"
631
- end
632
- end
633
- result
634
- end
635
-
636
- # Return the value returned by method +name+.
637
- def [](name)
638
- __send__ name
639
- end
640
- end
641
-
642
- module GeneratorMethods
643
- module Object
644
- # Converts this object to a string (calling #to_s), converts
645
- # it to a JSON string, and returns the result. This is a fallback, if no
646
- # special method #to_json was defined for some object.
647
- def to_json(*) to_s.to_json end
648
- end
649
-
650
- module Hash
651
- # Returns a JSON string containing a JSON object, that is unparsed from
652
- # this Hash instance.
653
- # _state_ is a JSON::State object, that can also be used to configure the
654
- # produced JSON string output further.
655
- # _depth_ is used to find out nesting depth, to indent accordingly.
656
- def to_json(state = nil, *)
657
- state = State.from_state(state)
658
- state.check_max_nesting
659
- json_transform(state)
660
- end
661
-
662
- private
663
-
664
- def json_shift(state)
665
- state.object_nl.empty? or return ''
666
- state.indent * state.depth
667
- end
668
-
669
- def json_transform(state)
670
- delim = ','
671
- delim << state.object_nl
672
- result = '{'
673
- result << state.object_nl
674
- depth = state.depth += 1
675
- first = true
676
- indent = !state.object_nl.empty?
677
- each { |key,value|
678
- result << delim unless first
679
- result << state.indent * depth if indent
680
- result << key.to_s.to_json(state)
681
- result << state.space_before
682
- result << ':'
683
- result << state.space
684
- result << value.to_json(state)
685
- first = false
686
- }
687
- depth = state.depth -= 1
688
- result << state.object_nl
689
- result << state.indent * depth if indent if indent
690
- result << '}'
691
- result
692
- end
693
- end
694
-
695
- module Array
696
- # Returns a JSON string containing a JSON array, that is unparsed from
697
- # this Array instance.
698
- # _state_ is a JSON::State object, that can also be used to configure the
699
- # produced JSON string output further.
700
- def to_json(state = nil, *)
701
- state = State.from_state(state)
702
- state.check_max_nesting
703
- json_transform(state)
704
- end
705
-
706
- private
707
-
708
- def json_transform(state)
709
- delim = ','
710
- delim << state.array_nl
711
- result = '['
712
- result << state.array_nl
713
- depth = state.depth += 1
714
- first = true
715
- indent = !state.array_nl.empty?
716
- each { |value|
717
- result << delim unless first
718
- result << state.indent * depth if indent
719
- result << value.to_json(state)
720
- first = false
721
- }
722
- depth = state.depth -= 1
723
- result << state.array_nl
724
- result << state.indent * depth if indent
725
- result << ']'
726
- end
727
- end
728
-
729
- module Integer
730
- # Returns a JSON string representation for this Integer number.
731
- def to_json(*) to_s end
732
- end
733
-
734
- module Float
735
- # Returns a JSON string representation for this Float number.
736
- def to_json(state = nil, *)
737
- state = State.from_state(state)
738
- case
739
- when infinite?
740
- if state.allow_nan?
741
- to_s
742
- else
743
- raise GeneratorError, "#{self} not allowed in JSON"
744
- end
745
- when nan?
746
- if state.allow_nan?
747
- to_s
748
- else
749
- raise GeneratorError, "#{self} not allowed in JSON"
750
- end
751
- else
752
- to_s
753
- end
754
- end
755
- end
756
-
757
- module String
758
- if defined?(::Encoding)
759
- # This string should be encoded with UTF-8 A call to this method
760
- # returns a JSON string encoded with UTF16 big endian characters as
761
- # \u????.
762
- def to_json(state = nil, *args)
763
- state = State.from_state(state)
764
- if encoding == ::Encoding::UTF_8
765
- string = self
766
- else
767
- string = encode(::Encoding::UTF_8)
768
- end
769
- if state.ascii_only?
770
- '"' << JSON.utf8_to_json_ascii(string) << '"'
771
- else
772
- '"' << JSON.utf8_to_json(string) << '"'
773
- end
774
- end
775
- else
776
- # This string should be encoded with UTF-8 A call to this method
777
- # returns a JSON string encoded with UTF16 big endian characters as
778
- # \u????.
779
- def to_json(state = nil, *args)
780
- state = State.from_state(state)
781
- if state.ascii_only?
782
- '"' << JSON.utf8_to_json_ascii(self) << '"'
783
- else
784
- '"' << JSON.utf8_to_json(self) << '"'
785
- end
786
- end
787
- end
788
-
789
- # Module that holds the extinding methods if, the String module is
790
- # included.
791
- module Extend
792
- # Raw Strings are JSON Objects (the raw bytes are stored in an
793
- # array for the key "raw"). The Ruby String can be created by this
794
- # module method.
795
- def json_create(o)
796
- o['raw'].pack('C*')
797
- end
798
- end
799
-
800
- # Extends _modul_ with the String::Extend module.
801
- def self.included(modul)
802
- modul.extend Extend
803
- end
804
-
805
- # This method creates a raw object hash, that can be nested into
806
- # other data structures and will be unparsed as a raw string. This
807
- # method should be used, if you want to convert raw strings to JSON
808
- # instead of UTF-8 strings, e. g. binary data.
809
- def to_json_raw_object
810
- {
811
- JSON.create_id => self.class.name,
812
- 'raw' => self.unpack('C*'),
813
- }
814
- end
815
-
816
- # This method creates a JSON text from the result of
817
- # a call to to_json_raw_object of this String.
818
- def to_json_raw(*args)
819
- to_json_raw_object.to_json(*args)
820
- end
821
- end
822
-
823
- module TrueClass
824
- # Returns a JSON string for true: 'true'.
825
- def to_json(*) 'true' end
826
- end
827
-
828
- module FalseClass
829
- # Returns a JSON string for false: 'false'.
830
- def to_json(*) 'false' end
831
- end
832
-
833
- module NilClass
834
- # Returns a JSON string for nil: 'null'.
835
- def to_json(*) 'null' end
836
- end
837
- end
838
- end
839
- end
840
- end
841
-
842
- module JSON
843
- class << self
844
- # If _object_ is string-like, parse the string and return the parsed result
845
- # as a Ruby data structure. Otherwise generate a JSON text from the Ruby
846
- # data structure object and return it.
847
- #
848
- # The _opts_ argument is passed through to generate/parse respectively. See
849
- # generate and parse for their documentation.
850
- def [](object, opts = {})
851
- if object.respond_to? :to_str
852
- JSON.parse(object.to_str, opts)
853
- else
854
- JSON.generate(object, opts)
855
- end
856
- end
857
-
858
- # Returns the JSON parser class that is used by JSON. This is either
859
- # JSON::Ext::Parser or JSON::Pure::Parser.
860
- attr_reader :parser
861
-
862
- # Set the JSON parser class _parser_ to be used by JSON.
863
- def parser=(parser) # :nodoc:
864
- @parser = parser
865
- remove_const :Parser if JSON.const_defined_in?(self, :Parser)
866
- const_set :Parser, parser
867
- end
868
-
869
- # Return the constant located at _path_. The format of _path_ has to be
870
- # either ::A::B::C or A::B::C. In any case, A has to be located at the top
871
- # level (absolute namespace path?). If there doesn't exist a constant at
872
- # the given path, an ArgumentError is raised.
873
- def deep_const_get(path) # :nodoc:
874
- path.to_s.split(/::/).inject(Object) do |p, c|
875
- case
876
- when c.empty? then p
877
- when JSON.const_defined_in?(p, c) then p.const_get(c)
878
- else
879
- begin
880
- p.const_missing(c)
881
- rescue NameError => e
882
- raise ArgumentError, "can't get const #{path}: #{e}"
883
- end
884
- end
885
- end
886
- end
887
-
888
- # Set the module _generator_ to be used by JSON.
889
- def generator=(generator) # :nodoc:
890
- old, $VERBOSE = $VERBOSE, nil
891
- @generator = generator
892
- generator_methods = generator::GeneratorMethods
893
- for const in generator_methods.constants
894
- klass = deep_const_get(const)
895
- modul = generator_methods.const_get(const)
896
- klass.class_eval do
897
- instance_methods(false).each do |m|
898
- m.to_s == 'to_json' and remove_method m
899
- end
900
- include modul
901
- end
902
- end
903
- self.state = generator::State
904
- const_set :State, self.state
905
- const_set :SAFE_STATE_PROTOTYPE, State.new
906
- const_set :FAST_STATE_PROTOTYPE, State.new(
907
- :indent => '',
908
- :space => '',
909
- :object_nl => "",
910
- :array_nl => "",
911
- :max_nesting => false
912
- )
913
- const_set :PRETTY_STATE_PROTOTYPE, State.new(
914
- :indent => ' ',
915
- :space => ' ',
916
- :object_nl => "\n",
917
- :array_nl => "\n"
918
- )
919
- ensure
920
- $VERBOSE = old
921
- end
922
-
923
- # Returns the JSON generator module that is used by JSON. This is
924
- # either JSON::Ext::Generator or JSON::Pure::Generator.
925
- attr_reader :generator
926
-
927
- # Returns the JSON generator state class that is used by JSON. This is
928
- # either JSON::Ext::Generator::State or JSON::Pure::Generator::State.
929
- attr_accessor :state
930
-
931
- # This is create identifier, which is used to decide if the _json_create_
932
- # hook of a class should be called. It defaults to 'json_class'.
933
- attr_accessor :create_id
934
- end
935
- self.create_id = 'json_class'
936
-
937
- NaN = 0.0/0
938
-
939
- Infinity = 1.0/0
940
-
941
- MinusInfinity = -Infinity
942
-
943
- # The base exception for JSON errors.
944
- class JSONError < StandardError; end
945
-
946
- # This exception is raised if a parser error occurs.
947
- class ParserError < JSONError; end
948
-
949
- # This exception is raised if the nesting of parsed data structures is too
950
- # deep.
951
- class NestingError < ParserError; end
952
-
953
- # :stopdoc:
954
- class CircularDatastructure < NestingError; end
955
- # :startdoc:
956
-
957
- # This exception is raised if a generator or unparser error occurs.
958
- class GeneratorError < JSONError; end
959
- # For backwards compatibility
960
- UnparserError = GeneratorError
961
-
962
- # This exception is raised if the required unicode support is missing on the
963
- # system. Usually this means that the iconv library is not installed.
964
- class MissingUnicodeSupport < JSONError; end
965
-
966
- module_function
967
-
968
- # Parse the JSON document _source_ into a Ruby data structure and return it.
969
- #
970
- # _opts_ can have the following
971
- # keys:
972
- # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
973
- # structures. Disable depth checking with :max_nesting => false. It defaults
974
- # to 19.
975
- # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
976
- # defiance of RFC 4627 to be parsed by the Parser. This option defaults
977
- # to false.
978
- # * *symbolize_names*: If set to true, returns symbols for the names
979
- # (keys) in a JSON object. Otherwise strings are returned. Strings are
980
- # the default.
981
- # * *create_additions*: If set to false, the Parser doesn't create
982
- # additions even if a matching class and create_id was found. This option
983
- # defaults to true.
984
- # * *object_class*: Defaults to Hash
985
- # * *array_class*: Defaults to Array
986
- def parse(source, opts = {})
987
- Parser.new(source, opts).parse
988
- end
989
-
990
- # Parse the JSON document _source_ into a Ruby data structure and return it.
991
- # The bang version of the parse method defaults to the more dangerous values
992
- # for the _opts_ hash, so be sure only to parse trusted _source_ documents.
993
- #
994
- # _opts_ can have the following keys:
995
- # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
996
- # structures. Enable depth checking with :max_nesting => anInteger. The parse!
997
- # methods defaults to not doing max depth checking: This can be dangerous
998
- # if someone wants to fill up your stack.
999
- # * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in
1000
- # defiance of RFC 4627 to be parsed by the Parser. This option defaults
1001
- # to true.
1002
- # * *create_additions*: If set to false, the Parser doesn't create
1003
- # additions even if a matching class and create_id was found. This option
1004
- # defaults to true.
1005
- def parse!(source, opts = {})
1006
- opts = {
1007
- :max_nesting => false,
1008
- :allow_nan => true
1009
- }.update(opts)
1010
- Parser.new(source, opts).parse
1011
- end
1012
-
1013
- # Generate a JSON document from the Ruby data structure _obj_ and return
1014
- # it. _state_ is * a JSON::State object,
1015
- # * or a Hash like object (responding to to_hash),
1016
- # * an object convertible into a hash by a to_h method,
1017
- # that is used as or to configure a State object.
1018
- #
1019
- # It defaults to a state object, that creates the shortest possible JSON text
1020
- # in one line, checks for circular data structures and doesn't allow NaN,
1021
- # Infinity, and -Infinity.
1022
- #
1023
- # A _state_ hash can have the following keys:
1024
- # * *indent*: a string used to indent levels (default: ''),
1025
- # * *space*: a string that is put after, a : or , delimiter (default: ''),
1026
- # * *space_before*: a string that is put before a : pair delimiter (default: ''),
1027
- # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
1028
- # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
1029
- # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
1030
- # generated, otherwise an exception is thrown if these values are
1031
- # encountered. This options defaults to false.
1032
- # * *max_nesting*: The maximum depth of nesting allowed in the data
1033
- # structures from which JSON is to be generated. Disable depth checking
1034
- # with :max_nesting => false, it defaults to 19.
1035
- #
1036
- # See also the fast_generate for the fastest creation method with the least
1037
- # amount of sanity checks, and the pretty_generate method for some
1038
- # defaults for pretty output.
1039
- def generate(obj, opts = nil)
1040
- if State === opts
1041
- state, opts = opts, nil
1042
- else
1043
- state = SAFE_STATE_PROTOTYPE.dup
1044
- end
1045
- if opts
1046
- if opts.respond_to? :to_hash
1047
- opts = opts.to_hash
1048
- elsif opts.respond_to? :to_h
1049
- opts = opts.to_h
1050
- else
1051
- raise TypeError, "can't convert #{opts.class} into Hash"
1052
- end
1053
- state = state.configure(opts)
1054
- end
1055
- state.generate(obj)
1056
- end
1057
-
1058
- # :stopdoc:
1059
- # I want to deprecate these later, so I'll first be silent about them, and
1060
- # later delete them.
1061
- alias unparse generate
1062
- module_function :unparse
1063
- # :startdoc:
1064
-
1065
- # Generate a JSON document from the Ruby data structure _obj_ and return it.
1066
- # This method disables the checks for circles in Ruby objects.
1067
- #
1068
- # *WARNING*: Be careful not to pass any Ruby data structures with circles as
1069
- # _obj_ argument because this will cause JSON to go into an infinite loop.
1070
- def fast_generate(obj, opts = nil)
1071
- if State === opts
1072
- state, opts = opts, nil
1073
- else
1074
- state = FAST_STATE_PROTOTYPE.dup
1075
- end
1076
- if opts
1077
- if opts.respond_to? :to_hash
1078
- opts = opts.to_hash
1079
- elsif opts.respond_to? :to_h
1080
- opts = opts.to_h
1081
- else
1082
- raise TypeError, "can't convert #{opts.class} into Hash"
1083
- end
1084
- state.configure(opts)
1085
- end
1086
- state.generate(obj)
1087
- end
1088
-
1089
- # :stopdoc:
1090
- # I want to deprecate these later, so I'll first be silent about them, and later delete them.
1091
- alias fast_unparse fast_generate
1092
- module_function :fast_unparse
1093
- # :startdoc:
1094
-
1095
- # Generate a JSON document from the Ruby data structure _obj_ and return it.
1096
- # The returned document is a prettier form of the document returned by
1097
- # #unparse.
1098
- #
1099
- # The _opts_ argument can be used to configure the generator. See the
1100
- # generate method for a more detailed explanation.
1101
- def pretty_generate(obj, opts = nil)
1102
- if State === opts
1103
- state, opts = opts, nil
1104
- else
1105
- state = PRETTY_STATE_PROTOTYPE.dup
1106
- end
1107
- if opts
1108
- if opts.respond_to? :to_hash
1109
- opts = opts.to_hash
1110
- elsif opts.respond_to? :to_h
1111
- opts = opts.to_h
1112
- else
1113
- raise TypeError, "can't convert #{opts.class} into Hash"
1114
- end
1115
- state.configure(opts)
1116
- end
1117
- state.generate(obj)
1118
- end
1119
-
1120
- # :stopdoc:
1121
- # I want to deprecate these later, so I'll first be silent about them, and later delete them.
1122
- alias pretty_unparse pretty_generate
1123
- module_function :pretty_unparse
1124
- # :startdoc:
1125
-
1126
- class << self
1127
- # The global default options for the JSON.load method:
1128
- # :max_nesting: false
1129
- # :allow_nan: true
1130
- # :quirks_mode: true
1131
- attr_accessor :load_default_options
1132
- end
1133
- self.load_default_options = {
1134
- :max_nesting => false,
1135
- :allow_nan => true,
1136
- :quirks_mode => true,
1137
- }
1138
-
1139
- # Load a ruby data structure from a JSON _source_ and return it. A source can
1140
- # either be a string-like object, an IO-like object, or an object responding
1141
- # to the read method. If _proc_ was given, it will be called with any nested
1142
- # Ruby object as an argument recursively in depth first order. The default
1143
- # options for the parser can be changed via the load_default_options method.
1144
- #
1145
- # This method is part of the implementation of the load/dump interface of
1146
- # Marshal and YAML.
1147
- def load(source, proc = nil)
1148
- opts = load_default_options
1149
- if source.respond_to? :to_str
1150
- source = source.to_str
1151
- elsif source.respond_to? :to_io
1152
- source = source.to_io.read
1153
- elsif source.respond_to?(:read)
1154
- source = source.read
1155
- end
1156
- if opts[:quirks_mode] && (source.nil? || source.empty?)
1157
- source = 'null'
1158
- end
1159
- result = parse(source, opts)
1160
- recurse_proc(result, &proc) if proc
1161
- result
1162
- end
1163
-
1164
- # Recursively calls passed _Proc_ if the parsed data structure is an _Array_ or _Hash_
1165
- def recurse_proc(result, &proc)
1166
- case result
1167
- when Array
1168
- result.each { |x| recurse_proc x, &proc }
1169
- proc.call result
1170
- when Hash
1171
- result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
1172
- proc.call result
1173
- else
1174
- proc.call result
1175
- end
1176
- end
1177
-
1178
- alias restore load
1179
- module_function :restore
1180
-
1181
- class << self
1182
- # The global default options for the JSON.dump method:
1183
- # :max_nesting: false
1184
- # :allow_nan: true
1185
- # :quirks_mode: true
1186
- attr_accessor :dump_default_options
1187
- end
1188
- self.dump_default_options = {
1189
- :max_nesting => false,
1190
- :allow_nan => true,
1191
- :quirks_mode => true,
1192
- }
1193
-
1194
- # Dumps _obj_ as a JSON string, i.e. calls generate on the object and returns
1195
- # the result.
1196
- #
1197
- # If anIO (an IO-like object or an object that responds to the write method)
1198
- # was given, the resulting JSON is written to it.
1199
- #
1200
- # If the number of nested arrays or objects exceeds _limit_, an ArgumentError
1201
- # exception is raised. This argument is similar (but not exactly the
1202
- # same!) to the _limit_ argument in Marshal.dump.
1203
- #
1204
- # The default options for the generator can be changed via the
1205
- # dump_default_options method.
1206
- #
1207
- # This method is part of the implementation of the load/dump interface of
1208
- # Marshal and YAML.
1209
- def dump(obj, anIO = nil, limit = nil)
1210
- if anIO and limit.nil?
1211
- anIO = anIO.to_io if anIO.respond_to?(:to_io)
1212
- unless anIO.respond_to?(:write)
1213
- limit = anIO
1214
- anIO = nil
1215
- end
1216
- end
1217
- opts = JSON.dump_default_options
1218
- limit and opts.update(:max_nesting => limit)
1219
- result = generate(obj, opts)
1220
- if anIO
1221
- anIO.write result
1222
- anIO
1223
- else
1224
- result
1225
- end
1226
- rescue JSON::NestingError
1227
- raise ArgumentError, "exceed depth limit"
1228
- end
1229
-
1230
- # Swap consecutive bytes of _string_ in place.
1231
- def self.swap!(string) # :nodoc:
1232
- 0.upto(string.size / 2) do |i|
1233
- break unless string[2 * i + 1]
1234
- string[2 * i], string[2 * i + 1] = string[2 * i + 1], string[2 * i]
1235
- end
1236
- string
1237
- end
1238
-
1239
- # Shortuct for iconv.
1240
- if ::String.method_defined?(:encode)
1241
- # Encodes string using Ruby's _String.encode_
1242
- def self.iconv(to, from, string)
1243
- string.encode(to, from)
1244
- end
1245
- else
1246
- require 'iconv'
1247
- # Encodes string using _iconv_ library
1248
- def self.iconv(to, from, string)
1249
- Iconv.conv(to, from, string)
1250
- end
1251
- end
1252
-
1253
- if ::Object.method(:const_defined?).arity == 1
1254
- def self.const_defined_in?(modul, constant)
1255
- modul.const_defined?(constant)
1256
- end
1257
- else
1258
- def self.const_defined_in?(modul, constant)
1259
- modul.const_defined?(constant, false)
1260
- end
1261
- end
1262
- end
1263
-
1264
- module ::Kernel
1265
- private
1266
-
1267
- # Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
1268
- # one line.
1269
- def j(*objs)
1270
- objs.each do |obj|
1271
- puts JSON::generate(obj, :allow_nan => true, :max_nesting => false)
1272
- end
1273
- nil
1274
- end
1275
-
1276
- # Ouputs _objs_ to STDOUT as JSON strings in a pretty format, with
1277
- # indentation and over many lines.
1278
- def jj(*objs)
1279
- objs.each do |obj|
1280
- puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
1281
- end
1282
- nil
1283
- end
1284
-
1285
- # If _object_ is string-like, parse the string and return the parsed result as
1286
- # a Ruby data structure. Otherwise, generate a JSON text from the Ruby data
1287
- # structure object and return it.
1288
- #
1289
- # The _opts_ argument is passed through to generate/parse respectively. See
1290
- # generate and parse for their documentation.
1291
- def JSON(object, *args)
1292
- if object.respond_to? :to_str
1293
- JSON.parse(object.to_str, args.first)
1294
- else
1295
- JSON.generate(object, args.first)
1296
- end
1297
- end
1298
- end
1299
-
1300
- # Extends any Class to include _json_creatable?_ method.
1301
- class ::Class
1302
- # Returns true if this class can be used to create an instance
1303
- # from a serialised JSON string. The class has to implement a class
1304
- # method _json_create_ that expects a hash as first parameter. The hash
1305
- # should include the required data.
1306
- def json_creatable?
1307
- respond_to?(:json_create)
1308
- end
1309
- end
1310
-
1311
- JSON.generator = JSON::Pure::Generator
1312
- JSON.parser = JSON::Pure::Parser
1313
- rescue LoadError
1314
- require File.join File.dirname(File.dirname(__FILE__)), 'vendor', 'json.rb'
1315
- end
1316
-
1317
- # It just gists.
1318
- module Gist
1319
- extend self
1320
-
1321
- VERSION = '4.6.2'
1322
-
1323
- # A list of clipboard commands with copy and paste support.
1324
- CLIPBOARD_COMMANDS = {
1325
- 'pbcopy' => 'pbpaste',
1326
- 'xclip' => 'xclip -o',
1327
- 'xsel -i' => 'xsel -o',
1328
- 'putclip' => 'getclip',
1329
- }
1330
-
1331
- GITHUB_API_URL = URI("https://api.github.com/")
1332
- GIT_IO_URL = URI("https://git.io")
1333
-
1334
- GITHUB_BASE_PATH = ""
1335
- GHE_BASE_PATH = "/api/v3"
1336
-
1337
- URL_ENV_NAME = "GITHUB_URL"
1338
-
1339
- USER_AGENT = "gist/#{VERSION} (Net::HTTP, #{RUBY_DESCRIPTION})"
1340
-
1341
- # Exception tag for errors raised while gisting.
1342
- module Error;
1343
- def self.exception(*args)
1344
- RuntimeError.new(*args).extend(self)
1345
- end
1346
- end
1347
- class ClipboardError < RuntimeError; include Error end
1348
-
1349
- # helper module for authentication token actions
1350
- module AuthTokenFile
1351
- def self.filename
1352
- if ENV.key?(URL_ENV_NAME)
1353
- File.expand_path "~/.gist.#{ENV[URL_ENV_NAME].gsub(/:/, '.').gsub(/[^a-z0-9.]/, '')}"
1354
- else
1355
- File.expand_path "~/.gist"
1356
- end
1357
- end
1358
-
1359
- def self.read
1360
- File.read(filename).chomp
1361
- end
1362
-
1363
- def self.write(token)
1364
- File.open(filename, 'w', 0600) do |f|
1365
- f.write token
1366
- end
1367
- end
1368
- end
1369
-
1370
- # auth token for authentication
1371
- #
1372
- # @return [String] string value of access token or `nil`, if not found
1373
- def auth_token
1374
- @token ||= AuthTokenFile.read rescue nil
1375
- end
1376
-
1377
- # Upload a gist to https://gist.github.com
1378
- #
1379
- # @param [String] content the code you'd like to gist
1380
- # @param [Hash] options more detailed options, see
1381
- # the documentation for {multi_gist}
1382
- #
1383
- # @see http://developer.github.com/v3/gists/
1384
- def gist(content, options = {})
1385
- filename = options[:filename] || default_filename
1386
- multi_gist({filename => content}, options)
1387
- end
1388
-
1389
- def default_filename
1390
- "gistfile1.txt"
1391
- end
1392
-
1393
- # Upload a gist to https://gist.github.com
1394
- #
1395
- # @param [Hash] files the code you'd like to gist: filename => content
1396
- # @param [Hash] options more detailed options
1397
- #
1398
- # @option options [String] :description the description
1399
- # @option options [Boolean] :public (false) is this gist public
1400
- # @option options [Boolean] :anonymous (false) is this gist anonymous
1401
- # @option options [String] :access_token (`File.read("~/.gist")`) The OAuth2 access token.
1402
- # @option options [String] :update the URL or id of a gist to update
1403
- # @option options [Boolean] :copy (false) Copy resulting URL to clipboard, if successful.
1404
- # @option options [Boolean] :open (false) Open the resulting URL in a browser.
1405
- # @option options [Boolean] :skip_empty (false) Skip gisting empty files.
1406
- # @option options [Symbol] :output (:all) The type of return value you'd like:
1407
- # :html_url gives a String containing the url to the gist in a browser
1408
- # :short_url gives a String contianing a git.io url that redirects to html_url
1409
- # :javascript gives a String containing a script tag suitable for embedding the gist
1410
- # :all gives a Hash containing the parsed json response from the server
1411
- #
1412
- # @return [String, Hash] the return value as configured by options[:output]
1413
- # @raise [Gist::Error] if something went wrong
1414
- #
1415
- # @see http://developer.github.com/v3/gists/
1416
- def multi_gist(files, options={})
1417
- json = {}
1418
-
1419
- json[:description] = options[:description] if options[:description]
1420
- json[:public] = !!options[:public]
1421
- json[:files] = {}
1422
-
1423
- files.each_pair do |(name, content)|
1424
- if content.to_s.strip == ""
1425
- raise "Cannot gist empty files" unless options[:skip_empty]
1426
- else
1427
- name = name == "-" ? default_filename : File.basename(name)
1428
- json[:files][name] = {:content => content}
1429
- end
1430
- end
1431
-
1432
- return if json[:files].empty? && options[:skip_empty]
1433
-
1434
- existing_gist = options[:update].to_s.split("/").last
1435
- if options[:anonymous]
1436
- access_token = nil
1437
- else
1438
- access_token = (options[:access_token] || auth_token())
1439
- end
1440
-
1441
- url = "#{base_path}/gists"
1442
- url << "/" << CGI.escape(existing_gist) if existing_gist.to_s != ''
1443
- url << "?access_token=" << CGI.escape(access_token) if access_token.to_s != ''
1444
-
1445
- request = Net::HTTP::Post.new(url)
1446
- request.body = JSON.dump(json)
1447
- request.content_type = 'application/json'
1448
-
1449
- retried = false
1450
-
1451
- begin
1452
- response = http(api_url, request)
1453
- if Net::HTTPSuccess === response
1454
- on_success(response.body, options)
1455
- else
1456
- raise "Got #{response.class} from gist: #{response.body}"
1457
- end
1458
- rescue => e
1459
- raise if retried
1460
- retried = true
1461
- retry
1462
- end
1463
-
1464
- rescue => e
1465
- raise e.extend Error
1466
- end
1467
-
1468
- # List all gists(private also) for authenticated user
1469
- # otherwise list public gists for given username (optional argument)
1470
- #
1471
- # @param [String] user
1472
- # @deprecated
1473
- #
1474
- # see https://developer.github.com/v3/gists/#list-gists
1475
- def list_gists(user = "")
1476
- url = "#{base_path}"
1477
-
1478
- if user == ""
1479
- access_token = auth_token()
1480
- if access_token.to_s != ''
1481
- url << "/gists?access_token=" << CGI.escape(access_token)
1482
-
1483
- request = Net::HTTP::Get.new(url)
1484
- response = http(api_url, request)
1485
-
1486
- pretty_gist(response)
1487
-
1488
- else
1489
- raise Error, "Not authenticated. Use 'gist --login' to login or 'gist -l username' to view public gists."
1490
- end
1491
-
1492
- else
1493
- url << "/users/#{user}/gists"
1494
-
1495
- request = Net::HTTP::Get.new(url)
1496
- response = http(api_url, request)
1497
-
1498
- pretty_gist(response)
1499
- end
1500
- end
1501
-
1502
- def list_all_gists(user = "")
1503
- url = "#{base_path}"
1504
-
1505
- if user == ""
1506
- access_token = auth_token()
1507
- if access_token.to_s != ''
1508
- url << "/gists?per_page=100&access_token=" << CGI.escape(access_token)
1509
- get_gist_pages(url)
1510
- else
1511
- raise Error, "Not authenticated. Use 'gist --login' to login or 'gist -l username' to view public gists."
1512
- end
1513
-
1514
- else
1515
- url << "/users/#{user}/gists?per_page=100"
1516
- get_gist_pages(url)
1517
- end
1518
-
1519
- end
1520
-
1521
- def read_gist(id, file_name=nil)
1522
- url = "#{base_path}/gists/#{id}"
1523
-
1524
- access_token = auth_token()
1525
- if access_token.to_s != ''
1526
- url << "?access_token=" << CGI.escape(access_token)
1527
- end
1528
-
1529
- request = Net::HTTP::Get.new(url)
1530
- response = http(api_url, request)
1531
-
1532
- if response.code == '200'
1533
- body = JSON.parse(response.body)
1534
- files = body["files"]
1535
-
1536
- if file_name
1537
- file = files[file_name]
1538
- raise Error, "Gist with id of #{id} and file #{file_name} does not exist." unless file
1539
- else
1540
- file = files.values.first
1541
- end
1542
-
1543
- puts file["content"]
1544
- else
1545
- raise Error, "Gist with id of #{id} does not exist."
1546
- end
1547
- end
1548
-
1549
- def delete_gist(id)
1550
- id = id.split("/").last
1551
- url = "#{base_path}/gists/#{id}"
1552
-
1553
- access_token = auth_token()
1554
- if access_token.to_s != ''
1555
- url << "?access_token=" << CGI.escape(access_token)
1556
-
1557
- request = Net::HTTP::Delete.new(url)
1558
- response = http(api_url, request)
1559
- else
1560
- raise Error, "Not authenticated. Use 'gist --login' to login."
1561
- end
1562
-
1563
- if response.code == '204'
1564
- puts "Deleted!"
1565
- else
1566
- raise Error, "Gist with id of #{id} does not exist."
1567
- end
1568
- end
1569
-
1570
- def get_gist_pages(url)
1571
-
1572
- request = Net::HTTP::Get.new(url)
1573
- response = http(api_url, request)
1574
- pretty_gist(response)
1575
-
1576
- link_header = response.header['link']
1577
-
1578
- if link_header
1579
- links = Hash[ link_header.gsub(/(<|>|")/, "").split(',').map { |link| link.split('; rel=') } ].invert
1580
- get_gist_pages(links['next']) if links['next']
1581
- end
1582
-
1583
- end
1584
-
1585
- # return prettified string result of response body for all gists
1586
- #
1587
- # @params [Net::HTTPResponse] response
1588
- # @return [String] prettified result of listing all gists
1589
- #
1590
- # see https://developer.github.com/v3/gists/#response
1591
- def pretty_gist(response)
1592
- body = JSON.parse(response.body)
1593
- if response.code == '200'
1594
- body.each do |gist|
1595
- description = "#{gist['description'] || gist['files'].keys.join(" ")} #{gist['public'] ? '' : '(secret)'}"
1596
- puts "#{gist['html_url']} #{description.tr("\n", " ")}\n"
1597
- $stdout.flush
1598
- end
1599
-
1600
- else
1601
- raise Error, body['message']
1602
- end
1603
- end
1604
-
1605
- # Convert long github urls into short git.io ones
1606
- #
1607
- # @param [String] url
1608
- # @return [String] shortened url, or long url if shortening fails
1609
- def shorten(url)
1610
- request = Net::HTTP::Post.new("/create")
1611
- request.set_form_data(:url => url)
1612
- response = http(GIT_IO_URL, request)
1613
- case response.code
1614
- when "200"
1615
- URI.join(GIT_IO_URL, response.body).to_s
1616
- when "201"
1617
- response['Location']
1618
- else
1619
- url
1620
- end
1621
- end
1622
-
1623
- # Convert github url into raw file url
1624
- #
1625
- # Unfortunately the url returns from github's api is legacy,
1626
- # we have to taking a HTTPRedirection before appending it
1627
- # with '/raw'. Let's looking forward for github's api fix :)
1628
- #
1629
- # @param [String] url
1630
- # @return [String] the raw file url
1631
- def rawify(url)
1632
- uri = URI(url)
1633
- request = Net::HTTP::Get.new(uri.path)
1634
- response = http(uri, request)
1635
- if Net::HTTPSuccess === response
1636
- url + '/raw'
1637
- elsif Net::HTTPRedirection === response
1638
- rawify(response.header['location'])
1639
- end
1640
- end
1641
-
1642
- # Log the user into gist.
1643
- #
1644
- # This method asks the user for a username and password, and tries to obtain
1645
- # and OAuth2 access token, which is then stored in ~/.gist
1646
- #
1647
- # @raise [Gist::Error] if something went wrong
1648
- # @param [Hash] credentials login details
1649
- # @option credentials [String] :username
1650
- # @option credentials [String] :password
1651
- # @see http://developer.github.com/v3/oauth/
1652
- def login!(credentials={})
1653
- puts "Obtaining OAuth2 access_token from github."
1654
- loop do
1655
- print "GitHub username: "
1656
- username = credentials[:username] || $stdin.gets.strip
1657
- print "GitHub password: "
1658
- password = credentials[:password] || begin
1659
- `stty -echo` rescue nil
1660
- $stdin.gets.strip
1661
- ensure
1662
- `stty echo` rescue nil
1663
- end
1664
- puts ""
1665
-
1666
- request = Net::HTTP::Post.new("#{base_path}/authorizations")
1667
- request.body = JSON.dump({
1668
- :scopes => [:gist],
1669
- :note => "The gist gem (#{Time.now})",
1670
- :note_url => "https://github.com/ConradIrwin/gist"
1671
- })
1672
- request.content_type = 'application/json'
1673
- request.basic_auth(username, password)
1674
-
1675
- response = http(api_url, request)
1676
-
1677
- if Net::HTTPUnauthorized === response && response['X-GitHub-OTP']
1678
- print "2-factor auth code: "
1679
- twofa_code = $stdin.gets.strip
1680
- puts ""
1681
-
1682
- request['X-GitHub-OTP'] = twofa_code
1683
- response = http(api_url, request)
1684
- end
1685
-
1686
- if Net::HTTPCreated === response
1687
- AuthTokenFile.write JSON.parse(response.body)['token']
1688
- puts "Success! #{ENV[URL_ENV_NAME] || "https://github.com/"}settings/tokens"
1689
- return
1690
- elsif Net::HTTPUnauthorized === response
1691
- puts "Error: #{JSON.parse(response.body)['message']}"
1692
- next
1693
- else
1694
- raise "Got #{response.class} from gist: #{response.body}"
1695
- end
1696
- end
1697
- rescue => e
1698
- raise e.extend Error
1699
- end
1700
-
1701
- # Return HTTP connection
1702
- #
1703
- # @param [URI::HTTP] The URI to which to connect
1704
- # @return [Net::HTTP]
1705
- def http_connection(uri)
1706
- env = ENV['http_proxy'] || ENV['HTTP_PROXY']
1707
- connection = if env
1708
- proxy = URI(env)
1709
- Net::HTTP::Proxy(proxy.host, proxy.port).new(uri.host, uri.port)
1710
- else
1711
- Net::HTTP.new(uri.host, uri.port)
1712
- end
1713
- if uri.scheme == "https"
1714
- connection.use_ssl = true
1715
- connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
1716
- end
1717
- connection.open_timeout = 10
1718
- connection.read_timeout = 10
1719
- connection
1720
- end
1721
-
1722
- # Run an HTTP operation
1723
- #
1724
- # @param [URI::HTTP] The URI to which to connect
1725
- # @param [Net::HTTPRequest] The request to make
1726
- # @return [Net::HTTPResponse]
1727
- def http(url, request)
1728
- request['User-Agent'] = USER_AGENT
1729
-
1730
- http_connection(url).start do |http|
1731
- http.request request
1732
- end
1733
- rescue Timeout::Error
1734
- raise "Could not connect to #{api_url}"
1735
- end
1736
-
1737
- # Called after an HTTP response to gist to perform post-processing.
1738
- #
1739
- # @param [String] body the text body from the github api
1740
- # @param [Hash] options more detailed options, see
1741
- # the documentation for {multi_gist}
1742
- def on_success(body, options={})
1743
- json = JSON.parse(body)
1744
-
1745
- output = case options[:output]
1746
- when :javascript
1747
- %Q{<script src="#{json['html_url']}.js"></script>}
1748
- when :html_url
1749
- json['html_url']
1750
- when :raw_url
1751
- rawify(json['html_url'])
1752
- when :short_url
1753
- shorten(json['html_url'])
1754
- when :short_raw_url
1755
- shorten(rawify(json['html_url']))
1756
- else
1757
- json
1758
- end
1759
-
1760
- Gist.copy(output.to_s) if options[:copy]
1761
- Gist.open(json['html_url']) if options[:open]
1762
-
1763
- output
1764
- end
1765
-
1766
- # Copy a string to the clipboard.
1767
- #
1768
- # @param [String] content
1769
- # @raise [Gist::Error] if no clipboard integration could be found
1770
- #
1771
- def copy(content)
1772
- IO.popen(clipboard_command(:copy), 'r+') { |clip| clip.print content }
1773
-
1774
- unless paste == content
1775
- message = 'Copying to clipboard failed.'
1776
-
1777
- if ENV["TMUX"] && clipboard_command(:copy) == 'pbcopy'
1778
- message << "\nIf you're running tmux on a mac, try http://robots.thoughtbot.com/post/19398560514/how-to-copy-and-paste-with-tmux-on-mac-os-x"
1779
- end
1780
-
1781
- raise Error, message
1782
- end
1783
- rescue Error => e
1784
- raise ClipboardError, e.message + "\nAttempted to copy: #{content}"
1785
- end
1786
-
1787
- # Get a string from the clipboard.
1788
- #
1789
- # @param [String] content
1790
- # @raise [Gist::Error] if no clipboard integration could be found
1791
- def paste
1792
- `#{clipboard_command(:paste)}`
1793
- end
1794
-
1795
- # Find command from PATH environment.
1796
- #
1797
- # @param [String] cmd command name to find
1798
- # @param [String] options PATH environment variable
1799
- # @return [String] the command found
1800
- def which(cmd, path=ENV['PATH'])
1801
- if RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|bccwin|cygwin/
1802
- path.split(File::PATH_SEPARATOR).each {|dir|
1803
- f = File.join(dir, cmd+".exe")
1804
- return f if File.executable?(f) && !File.directory?(f)
1805
- }
1806
- nil
1807
- else
1808
- return system("which #{cmd} > /dev/null 2>&1")
1809
- end
1810
- end
1811
-
1812
- # Get the command to use for the clipboard action.
1813
- #
1814
- # @param [Symbol] action either :copy or :paste
1815
- # @return [String] the command to run
1816
- # @raise [Gist::ClipboardError] if no clipboard integration could be found
1817
- def clipboard_command(action)
1818
- command = CLIPBOARD_COMMANDS.keys.detect do |cmd|
1819
- which cmd
1820
- end
1821
- raise ClipboardError, <<-EOT unless command
1822
- Could not find copy command, tried:
1823
- #{CLIPBOARD_COMMANDS.values.join(' || ')}
1824
- EOT
1825
- action == :copy ? command : CLIPBOARD_COMMANDS[command]
1826
- end
1827
-
1828
- # Open a URL in a browser.
1829
- #
1830
- # @param [String] url
1831
- # @raise [RuntimeError] if no browser integration could be found
1832
- #
1833
- # This method was heavily inspired by defunkt's Gist#open,
1834
- # @see https://github.com/defunkt/gist/blob/bca9b29/lib/gist.rb#L157
1835
- def open(url)
1836
- command = if ENV['BROWSER']
1837
- ENV['BROWSER']
1838
- elsif RUBY_PLATFORM =~ /darwin/
1839
- 'open'
1840
- elsif RUBY_PLATFORM =~ /linux/
1841
- %w(
1842
- sensible-browser
1843
- xdg-open
1844
- firefox
1845
- firefox-bin
1846
- ).detect do |cmd|
1847
- which cmd
1848
- end
1849
- elsif ENV['OS'] == 'Windows_NT' || RUBY_PLATFORM =~ /djgpp|(cyg|ms|bcc)win|mingw|wince/i
1850
- 'start ""'
1851
- else
1852
- raise "Could not work out how to use a browser."
1853
- end
1854
-
1855
- `#{command} #{url}`
1856
- end
1857
-
1858
- # Get the API base path
1859
- def base_path
1860
- ENV.key?(URL_ENV_NAME) ? GHE_BASE_PATH : GITHUB_BASE_PATH
1861
- end
1862
-
1863
- # Get the API URL
1864
- def api_url
1865
- ENV.key?(URL_ENV_NAME) ? URI(ENV[URL_ENV_NAME]) : GITHUB_API_URL
1866
- end
1867
-
1868
- def legacy_private_gister?
1869
- return unless which('git')
1870
- `git config --global gist.private` =~ /\Ayes|1|true|on\z/i
1871
- end
1872
-
1873
- def should_be_public?(options={})
1874
- if options.key? :private
1875
- !options[:private]
1876
- else
1877
- !Gist.legacy_private_gister?
1878
- end
1879
- end
1880
- end
1881
- #!/usr/bin/env ruby
1882
-
1883
- # Silence Ctrl-C's
1884
- trap('INT'){ exit 1 }
1885
-
1886
- if Signal.list.include? 'PIPE'
1887
- trap('PIPE', 'EXIT')
1888
- end
1889
-
1890
- require 'optparse'
1891
-
1892
- # For the holdings of options.
1893
- options = {}
1894
- filenames = []
1895
-
1896
- OptionParser.new do |opts|
1897
- executable_name = File.split($0)[1]
1898
- opts.banner = <<-EOS
1899
- Gist (v#{Gist::VERSION}) lets you upload to https://gist.github.com/
1900
-
1901
- The content to be uploaded can be passed as a list of files, if none are
1902
- specified STDIN will be read. The default filename for STDIN is "a.rb", and all
1903
- filenames can be overridden by repeating the "-f" flag. The most useful reason
1904
- to do this is to change the syntax highlighting.
1905
-
1906
- If you'd like your gists to be associated with your GitHub account, so that you
1907
- can edit them and find them in future, first use `gist --login` to obtain an
1908
- Oauth2 access token. This is stored and used by gist in the future.
1909
-
1910
- Private gists do not have guessable URLs and can be created with "-p", you can
1911
- also set the description at the top of the gist by passing "-d".
1912
-
1913
- Anonymous gists are not associated with your GitHub account, they can be created
1914
- with "-a" even after you have used "gist --login".
1915
-
1916
- If you would like to shorten the resulting gist URL, use the -s flag. This will
1917
- use GitHub's URL shortener, git.io. You can also use -R to get the link to the
1918
- raw gist.
1919
-
1920
- To copy the resulting URL to your clipboard you can use the -c option, or to
1921
- just open it directly in your browser, use -o. Using the -e option will copy the
1922
- embeddable URL to the clipboard. You can add `alias gist='gist -c'` to your
1923
- shell's rc file to configure this behaviour by default.
1924
-
1925
- Instead of creating a new gist, you can update an existing one by passing its ID
1926
- or URL with "-u". For this to work, you must be logged in, and have created the
1927
- original gist with the same GitHub account.
1928
-
1929
- If you want to skip empty files, use the --skip-empty flag. If all files are
1930
- empty no gist will be created.
1931
-
1932
- Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL]
1933
- [--skip-empty] [-P] [-f NAME|-t EXT]* FILE*
1934
- #{executable_name} --login
1935
- #{executable_name} [-l|-r]
1936
-
1937
- EOS
1938
-
1939
- opts.on("--login", "Authenticate gist on this computer.") do
1940
- Gist.login!
1941
- exit
1942
- end
1943
-
1944
- opts.on("-f", "--filename [NAME.EXTENSION]", "Sets the filename and syntax type.") do |filename|
1945
- filenames << filename
1946
- options[:filename] = filename
1947
- end
1948
-
1949
- opts.on("-t", "--type [EXTENSION]", "Sets the file extension and syntax type.") do |extension|
1950
- filenames << "foo.#{extension}"
1951
- options[:filename] = "foo.#{extension}"
1952
- end
1953
-
1954
- opts.on("-p", "--private", "Makes your gist private.") do
1955
- options[:private] = true
1956
- end
1957
-
1958
- opts.on("--no-private") do
1959
- options[:private] = false
1960
- end
1961
-
1962
- opts.on("-d", "--description DESCRIPTION", "Adds a description to your gist.") do |description|
1963
- options[:description] = description
1964
- end
1965
-
1966
- opts.on("-s", "--shorten", "Shorten the gist URL using git.io.") do |shorten|
1967
- options[:shorten] = shorten
1968
- end
1969
-
1970
- opts.on("-u", "--update [ URL | ID ]", "Update an existing gist.") do |update|
1971
- options[:update] = update
1972
- end
1973
-
1974
- opts.on("-a", "--anonymous", "Create an anonymous gist.") do
1975
- options[:anonymous] = true
1976
- end
1977
-
1978
- opts.on("-c", "--copy", "Copy the resulting URL to the clipboard") do
1979
- options[:copy] = true
1980
- end
1981
-
1982
- opts.on("-e", "--embed", "Copy the embed code for the gist to the clipboard") do
1983
- options[:embed] = true
1984
- options[:copy] = true
1985
- end
1986
-
1987
- opts.on("-o", "--open", "Open the resulting URL in a browser") do
1988
- options[:open] = true
1989
- end
1990
-
1991
- opts.on("--no-open")
1992
-
1993
- opts.on("--skip-empty", "Skip gisting empty files") do
1994
- options[:skip_empty] = true
1995
- end
1996
-
1997
- opts.on("-P", "--paste", "Paste from the clipboard to gist") do
1998
- options[:paste] = true
1999
- end
2000
-
2001
- opts.on("-R", "--raw", "Display raw URL of the new gist") do
2002
- options[:raw] = true
2003
- end
2004
-
2005
- opts.on("-l", "--list [USER]", "List all gists for user") do |user|
2006
- options[:list] = user
2007
- end
2008
-
2009
- opts.on("-r", "--read ID [FILENAME]", "Read a gist and print out the contents") do |id|
2010
- options[:read] = id
2011
- end
2012
-
2013
- opts.on("--delete [ URL | ID ]", "Delete a gist") do |id|
2014
- options[:delete] = id
2015
- end
2016
-
2017
- opts.on_tail("-h","--help", "Show this message.") do
2018
- puts opts
2019
- exit
2020
- end
2021
-
2022
- opts.on_tail("-v", "--version", "Print the version.") do
2023
- puts "gist v#{Gist::VERSION}"
2024
- exit
2025
- end
2026
-
2027
- end.parse!
2028
-
2029
- begin
2030
- options[:output] = if options[:embed] && options[:shorten]
2031
- raise Gist::Error, "--embed does not make sense with --shorten"
2032
- elsif options[:embed]
2033
- :javascript
2034
- elsif options[:shorten] and options[:raw]
2035
- :short_raw_url
2036
- elsif options[:shorten]
2037
- :short_url
2038
- elsif options[:raw]
2039
- :raw_url
2040
- else
2041
- :html_url
2042
- end
2043
-
2044
- options[:public] = Gist.should_be_public?(options)
2045
-
2046
- if options.key? :list
2047
- if options[:list]
2048
- Gist.list_all_gists(options[:list])
2049
- else
2050
- Gist.list_all_gists
2051
- end
2052
- exit
2053
- end
2054
-
2055
- if options.key? :read
2056
- file_name = ARGV.first
2057
- Gist.read_gist(options[:read], file_name)
2058
- exit
2059
- end
2060
-
2061
- if options.key? :delete
2062
- Gist.delete_gist(options[:delete])
2063
- exit
2064
- end
2065
-
2066
- if options[:paste]
2067
- puts Gist.gist(Gist.paste, options)
2068
- else
2069
- to_read = ARGV.empty? ? ['-'] : ARGV
2070
- files = {}
2071
- to_read.zip(filenames).each do |(file, name)|
2072
- files[name || file] =
2073
- begin
2074
- if file == '-'
2075
- $stderr.puts "(type a gist. <ctrl-c> to cancel, <ctrl-d> when done)" if $stdin.tty?
2076
- STDIN.read
2077
- else
2078
- File.read(File.expand_path(file))
2079
- end
2080
- rescue => e
2081
- raise e.extend(Gist::Error)
2082
- end
2083
- end
2084
-
2085
- output = Gist.multi_gist(files, options)
2086
- puts output if output
2087
- end
2088
-
2089
- rescue Gist::Error => e
2090
- puts "Error: #{e.message}"
2091
- exit 1
2092
- end