jiffy 1.0.1 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe32595cfa71cdbb4d6ab8aadab3da303ced671f
4
- data.tar.gz: 3db1aeb55a7e6f78ce15a19d2240e4bcb530134c
3
+ metadata.gz: dff94c8019e36bd2ba0d85e47a6dc95a31d701c5
4
+ data.tar.gz: 0e018b5041a4dd2da6748e546524ccd795132b0e
5
5
  SHA512:
6
- metadata.gz: 4a759a9452c53cdefe2e9d724a53eddb415491104ec8af2c9f1ed1e85d94a6186fdc157352467d61af87052bb283a179d7aaad29bb53e284de0468a19f8f0ac9
7
- data.tar.gz: e51d267574c1953e73b56d9c96050a2b59ef3d121142900306cfb66a420bc87c5fb3feb39917d8e413be4cfba9bc4d098e32f1872d94a0f7c71a32003b911d0b
6
+ metadata.gz: 1b8f39061d4c55c291d56a3c074b29adcbbc8843fd67c82034f6ef6f1b5df6a98d1d676c66b684416e5beaae384a853a14ad6858ed302c85d81df2467fe1adae
7
+ data.tar.gz: edd9b3fe0cb7b7b1bf1db304e8106d953a7b12f0de66879f05ded532e9e137efd28ad30ce1bd5fd95c1dceb13467a50862417fe8b50db7a8afe337677c059dab
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- jiffy (1.0.1)
4
+ jiffy (1.0.3)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -20,13 +20,13 @@ $ gem install jiffy
20
20
  It can be installed system-wide using the following options.
21
21
 
22
22
  ```
23
- $ gem install --no-user-install -i "$(ruby -e'puts Gem.default_dir')" -n /usr/bin jiffy
23
+ $ gem install --no-user-install -i "$(ruby -e'puts Gem.default_dir')" -n /usr/local/bin jiffy
24
24
  ```
25
25
 
26
26
  ### Arch Linux
27
27
 
28
28
  ```
29
- $ yaourt -Syua ruby-jiffy
29
+ $ yaourt -S ruby-jiffy
30
30
  ```
31
31
 
32
32
  ## Usage
@@ -104,11 +104,23 @@ Tested against the following Ruby versions.
104
104
 
105
105
  ## Changelog
106
106
 
107
+ ### 1.0.3
108
+
109
+ * Fixed an issue with the gemspec.
110
+
111
+ ### 1.0.2
112
+
113
+ * Missing read permissions is now handled properly.
114
+ * Non-existing file as argument is now handled properly.
115
+ * Directory as argument is now handled properly.
116
+ * Output now always ends with a newline.
117
+ * #read is switched out in favor of #readpartial.
118
+
107
119
  ### 1.0.1
108
120
 
109
121
  * The application is renamed Jiffy.
110
122
  * The executable may now read from standard input.
111
- * SIGTERM and SIGINT is now handled properly and a ruby stacktrace is now shown.
123
+ * SIGTERM and SIGINT is now handled properly and a ruby stacktrace is not shown.
112
124
 
113
125
  ### 1.0.0
114
126
 
data/bin/jiffy CHANGED
@@ -32,15 +32,10 @@ Signal.trap("TERM") do
32
32
  exit 1
33
33
  end
34
34
 
35
- begin
36
- if ARGV.empty?
37
- Jiffy.new(in: STDIN).format
38
- else
39
- Jiffy.new(in: ARGF).format
40
- end
41
- rescue Jiffy::UnparseableError => e
42
- $stderr.puts e
43
- exit! 1
44
- rescue Errno::EPIPE
45
- # Do nothing
46
- end
35
+ result = if ARGV.empty?
36
+ Jiffy.new(in: STDIN).cl_format(err: STDERR)
37
+ else
38
+ Jiffy.new(in: ARGF).cl_format(err: STDERR)
39
+ end
40
+
41
+ exit 1 unless result
data/jiffy.gemspec CHANGED
@@ -4,7 +4,7 @@ Gem::Specification.new do |s|
4
4
  s.name = 'jiffy'
5
5
  s.version = Jiffy::VERSION
6
6
  s.license = 'MIT'
7
- s.date = '2014-12-03'
7
+ s.date = '2014-12-14'
8
8
 
9
9
  s.summary = 'A streaming-based JSON formatter in Ruby.'
10
10
  s.description = 'Jiffy utilizes Ragel in order to parse and continuously format JSON data. This allows it to achieve a constant memory usage, independent of the input size.'
@@ -30,6 +30,7 @@ Gem::Specification.new do |s|
30
30
  lib/jiffy/parsers/json_string.rl
31
31
  lib/jiffy/parsers/json_value.rb
32
32
  lib/jiffy/parsers/json_value.rl
33
+ lib/jiffy/array_mimicking_io.rb
33
34
  lib/jiffy/json_outputter.rb
34
35
  lib/jiffy/version.rb
35
36
  lib/jiffy.rb
@@ -0,0 +1,37 @@
1
+ class Jiffy
2
+ class ArrayMimickingIO
3
+ CHUNK_SIZE = 1_000_000 # 1 MB
4
+
5
+ attr_accessor :io, :chunk, :bytes_read
6
+
7
+ def initialize(io)
8
+ @io = io
9
+ @chunk = []
10
+ @bytes_read = 0
11
+ end
12
+
13
+ def [](nth_byte)
14
+ read_chunk unless has_nth_byte?(nth_byte)
15
+
16
+ fetch_nth_byte(nth_byte)
17
+ end
18
+
19
+ private
20
+
21
+ def fetch_nth_byte(nth_byte)
22
+ index = nth_byte - bytes_read + chunk.length
23
+
24
+ chunk[index]
25
+ end
26
+
27
+ def has_nth_byte?(nth_byte)
28
+ bytes_read > nth_byte
29
+ end
30
+
31
+ def read_chunk
32
+ @chunk = @io.readpartial(CHUNK_SIZE).codepoints
33
+
34
+ @bytes_read += @chunk.length
35
+ end
36
+ end
37
+ end
@@ -121,9 +121,9 @@ self.json_en_main = 1;
121
121
  def parse_json
122
122
  pe = :ignored
123
123
  eof = :ignored
124
- leftover = []
125
124
 
126
-
125
+ begin
126
+
127
127
  # line 128 "json.rb"
128
128
  begin
129
129
  p ||= 0
@@ -132,14 +132,8 @@ begin
132
132
  end
133
133
 
134
134
  # line 43 "json.rl"
135
-
136
- while chunk = io.read(1_000_000)
137
- self.data = leftover + chunk.unpack("c*")
138
- p ||= 0
139
- pe = data.length
140
-
141
135
 
142
- # line 143 "json.rb"
136
+ # line 137 "json.rb"
143
137
  begin
144
138
  _klen, _trans, _keys, _acts, _nacts = nil
145
139
  _goto_level = 0
@@ -256,7 +250,7 @@ when 1 then
256
250
 
257
251
  end
258
252
  end
259
- # line 260 "json.rb"
253
+ # line 254 "json.rb"
260
254
  end # action switch
261
255
  end
262
256
  end
@@ -283,10 +277,14 @@ when 1 then
283
277
  end
284
278
  end
285
279
 
286
- # line 50 "json.rl"
280
+ # line 44 "json.rl"
281
+ rescue EOFError
282
+ if p < data.bytes_read || data.bytes_read == 0
283
+ raise UnexpectedEndError, 'Unexpected end of input'
284
+ end
287
285
  end
288
286
 
289
- raise_unparseable p unless p == pe
287
+ raise_unparseable p unless p == data.bytes_read
290
288
  end
291
289
  end
292
290
  end
@@ -37,19 +37,17 @@ class Jiffy
37
37
  def parse_json
38
38
  pe = :ignored
39
39
  eof = :ignored
40
- leftover = []
41
-
42
- %% write init;
43
-
44
- while chunk = io.read(1_000_000)
45
- self.data = leftover + chunk.unpack("c*")
46
- p ||= 0
47
- pe = data.length
48
40
 
41
+ begin
42
+ %% write init;
49
43
  %% write exec;
44
+ rescue EOFError
45
+ if p < data.bytes_read || data.bytes_read == 0
46
+ raise UnexpectedEndError, 'Unexpected end of input'
47
+ end
50
48
  end
51
49
 
52
- raise_unparseable p unless p == pe
50
+ raise_unparseable p unless p == data.bytes_read
53
51
  end
54
52
  end
55
53
  end
data/lib/jiffy/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Jiffy
2
- VERSION = '1.0.1'
2
+ VERSION = '1.0.3'
3
3
  end
data/lib/jiffy.rb CHANGED
@@ -4,6 +4,7 @@ require 'jiffy/parsers/json_float'
4
4
  require 'jiffy/parsers/json_object'
5
5
  require 'jiffy/parsers/json_string'
6
6
  require 'jiffy/parsers/json_value'
7
+ require 'jiffy/array_mimicking_io'
7
8
  require 'jiffy/json_outputter'
8
9
 
9
10
  class Jiffy
@@ -29,22 +30,64 @@ class Jiffy
29
30
  def initialize(options = {})
30
31
  if options[:in].is_a?(String)
31
32
  @io = File.open(options[:in])
32
- elsif options[:in].respond_to?(:read)
33
+ elsif options[:in].respond_to?(:readpartial)
33
34
  @io = options[:in]
34
35
  else
35
36
  raise ArgumentError, 'Invalid input source'
36
37
  end
37
38
 
39
+ @data = ArrayMimickingIO.new(@io)
40
+
38
41
  @outputter = JsonOutputter.new(options)
39
42
  end
40
43
 
41
- private
44
+ def cl_format(options = {})
45
+ format
42
46
 
43
- def raise_unparseable(p)
44
- if !@io.closed? && @io.eof? && @data.length == p
45
- raise UnexpectedEndError, 'Unexpected end of input'
47
+ @outputter.t :char, "\n"
48
+
49
+ true
50
+ rescue Errno::EACCES
51
+ err = options[:err] || $stderr
52
+
53
+ if @io.respond_to? :filename
54
+ err.write "jiffy: #{@io.filename}: Permission denied\n"
46
55
  else
47
- raise UnparseableError, "Unexpected token at position #{p}"
56
+ err.write "jiffy: Permission denied\n"
48
57
  end
58
+
59
+ false
60
+ rescue Errno::ENOENT
61
+ err = options[:err] || $stderr
62
+
63
+ if @io.respond_to? :filename
64
+ err.write "jiffy: #{@io.filename}: No such file or directory\n"
65
+ else
66
+ err.write "jiffy: No such file or directory\n"
67
+ end
68
+
69
+ false
70
+ rescue Errno::EISDIR
71
+ err = options[:err] || $stderr
72
+
73
+ if @io.respond_to? :filename
74
+ err.write "jiffy: #{@io.filename}: Is a directory\n"
75
+ else
76
+ err.write "jiffy: Is a directory\n"
77
+ end
78
+
79
+ false
80
+ rescue UnexpectedEndError, UnparseableError => e
81
+ err = options[:err] || $stderr
82
+
83
+ err.write e.message << "\n"
84
+
85
+ false
86
+ end
87
+
88
+ private
89
+
90
+ def raise_unparseable(p)
91
+ raise UnparseableError, "Unexpected token at position #{p}"
49
92
  end
50
93
  end
data/test/jiffy_test.rb CHANGED
@@ -4,33 +4,85 @@ require 'stringio'
4
4
  require 'minitest/autorun'
5
5
  require 'jiffy'
6
6
 
7
+ valid_json = '["Valid JSON"]'
8
+ invalid_json = '["Invalid" "JSON"]'
9
+ incomplete_json = '["Incomplete JSON'
10
+
11
+ def it_should_properly_handle(exception, options)
12
+ io = Object.new.tap do |io|
13
+ io.define_singleton_method :readpartial do |*|
14
+ raise exception
15
+ end
16
+ end
17
+
18
+ it "should return false upon #{exception.inspect}" do
19
+ assert_equal false, Jiffy.new(in: io, out: StringIO.new).cl_format(err: StringIO.new)
20
+ end
21
+
22
+ it "should write #{options[:with]} to :stderr upon #{exception.inspect}" do
23
+ err = StringIO.new
24
+
25
+ Jiffy.new(in: io, out: StringIO.new).cl_format(err: err)
26
+
27
+ assert_includes err.string, options[:with]
28
+ end
29
+
30
+ it ":stderr should end with a newline upon #{exception.inspect}" do
31
+ err = StringIO.new
32
+
33
+ Jiffy.new(in: io, out: StringIO.new).cl_format(err: err)
34
+
35
+ assert_equal "\n", err.string[-1]
36
+ end
37
+ end
38
+
7
39
  describe Jiffy do
8
40
  positive_examples = Dir[File.join(File.dirname(__FILE__), 'positive-examples', '*')]
9
41
 
10
- positive_examples.each do |example|
11
- it "should correctly format #{File.basename(example)}" do
12
- out = StringIO.new
42
+ describe '#format' do
43
+ positive_examples.each do |example|
44
+ it "should format #{File.basename(example)} without raising an exception" do
45
+ out = StringIO.new
13
46
 
14
- Jiffy.new(in: example, out: out).format
47
+ Jiffy.new(in: example, out: out).format
15
48
 
16
- assert_equal(out.string, File.read(example).strip)
49
+ assert_equal(out.string, File.read(example).strip)
50
+ end
17
51
  end
18
- end
19
52
 
20
- negative_examples = Dir[File.join(File.dirname(__FILE__), 'negative-examples', '*')]
53
+ negative_examples = Dir[File.join(File.dirname(__FILE__), 'negative-examples', '*')]
21
54
 
22
- negative_examples.each do |example|
23
- it "should not format #{File.basename(example)}" do
24
- out = StringIO.new
55
+ negative_examples.each do |example|
56
+ it "should raise an exception when formatting #{File.basename(example)}" do
57
+ out = StringIO.new
58
+
59
+ assert_raises Jiffy::UnexpectedEndError, Jiffy::UnparseableError do
60
+ Jiffy.new(in: example, out: out).format
61
+ end
62
+ end
63
+ end
25
64
 
26
- expected_exception = if /unclosed/ =~ example
27
- Jiffy::UnexpectedEndError
28
- else
29
- Jiffy::UnparseableError
30
- end
65
+ it 'should raise UnexpectedEndError on valid, but incomplete JSON input' do
66
+ example = StringIO.new incomplete_json
31
67
 
32
- assert_raises expected_exception do
33
- Jiffy.new(in: example, out: out).format
68
+ assert_raises Jiffy::UnexpectedEndError do
69
+ Jiffy.new(in: example, out: StringIO.new).format
70
+ end
71
+ end
72
+
73
+ it 'should raise UnexpectedEndError on empty input' do
74
+ example = StringIO.new ""
75
+
76
+ assert_raises Jiffy::UnexpectedEndError do
77
+ Jiffy.new(in: example, out: StringIO.new).format
78
+ end
79
+ end
80
+
81
+ it 'should raise UnparseableError on invalid JSON input' do
82
+ example = StringIO.new invalid_json
83
+
84
+ assert_raises Jiffy::UnparseableError do
85
+ Jiffy.new(in: example, out: StringIO.new).format
34
86
  end
35
87
  end
36
88
  end
@@ -44,4 +96,38 @@ describe Jiffy do
44
96
  end
45
97
  end
46
98
  end
99
+
100
+ describe '#cl_format' do
101
+ it_should_properly_handle Jiffy::UnexpectedEndError.new('Unexpected end of input'), with: 'Unexpected end of input'
102
+ it_should_properly_handle Jiffy::UnparseableError.new('Unexpected token at position'), with: 'Unexpected token at position'
103
+ it_should_properly_handle Errno::EACCES, with: 'jiffy: Permission denied'
104
+ it_should_properly_handle Errno::ENOENT, with: 'jiffy: No such file or directory'
105
+ it_should_properly_handle Errno::EISDIR, with: 'jiffy: Is a directory'
106
+
107
+ it 'should return true upon valid input' do
108
+ example = StringIO.new valid_json
109
+
110
+ assert_equal true, Jiffy.new(in: example, out: StringIO.new).cl_format
111
+ end
112
+
113
+ it 'should not write to :stderr upon valid input' do
114
+ example = StringIO.new valid_json
115
+
116
+ err = StringIO.new
117
+
118
+ Jiffy.new(in: example, out: StringIO.new).cl_format(err: err)
119
+
120
+ assert_equal "", err.string
121
+ end
122
+
123
+ it ':stdout should end with a newline upon valid input' do
124
+ example = StringIO.new valid_json
125
+
126
+ out = StringIO.new
127
+
128
+ Jiffy.new(in: example, out: out).cl_format
129
+
130
+ assert_equal "\n", out.string[-1]
131
+ end
132
+ end
47
133
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jiffy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Amundsen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-03 00:00:00.000000000 Z
11
+ date: 2014-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -54,6 +54,7 @@ files:
54
54
  - bin/jiffy
55
55
  - jiffy.gemspec
56
56
  - lib/jiffy.rb
57
+ - lib/jiffy/array_mimicking_io.rb
57
58
  - lib/jiffy/json_outputter.rb
58
59
  - lib/jiffy/parsers/json.rb
59
60
  - lib/jiffy/parsers/json.rl