gist 4.6.2 → 6.0.0

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.
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