yagni_json_encoder 0.0.2

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3461fb18bd4f2d2a69eaaeb655af5ad290fe3e60
4
+ data.tar.gz: 7b79546f667857112a48fa2b88b41d985d2cc73b
5
+ SHA512:
6
+ metadata.gz: 713ac3358afa5e9bb1bf2b4bda4e4265efc0bda80a549459623d804076295493eed8cf424cd86fb6b0b3f2beb471914e7e56178692ac10c940db99ef067e57e1
7
+ data.tar.gz: 311736b35fdac8db60fab3db9dc3f22a425e8e395a3662dd8f1bf4716542a62d89f4c3da24c85d071f02e2a91bafec6a770956bab82ce3240fdc1894393d236b
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2016 Ian Clay Ker-Seymer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # YagniJsonEncoder
2
+
3
+ [![Build Status](https://travis-ci.org/ianks/yagni_json_encoder.svg?branch=master)](https://travis-ci.org/ianks/yagni_json_encoder)
4
+
5
+ This gem overrides the [default ActiveSupport JSON
6
+ encoder](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/json/encoding.rb)
7
+ with a faster encoder which makes a few assumptions about your app.
8
+
9
+ 1. You do not need the escape HTML entities in your JSON
10
+ 2. You do not need any special escaping besides that provided by the JSON
11
+ standard.
12
+
13
+ Under the hood, this app removes Rails' special JSON escaping, and relies on
14
+ [Oj](https://github.com/ohler55/oj) to do the heavy lifting of JSON encoding.
15
+
16
+
17
+ ## Why?
18
+
19
+ By default, Rails plays it safe and escapes `\u2028` and `\u2029`. In order to
20
+ do this, a `#gsub` call (O(n) time complexity) is required on every string it
21
+ encounters. I do not interface with old browsers, so escaping these characters
22
+ is useless to me. Instead, we dont escape these characters, and let Oj do all
23
+ the heavy JSON encoding work.
24
+
25
+
26
+ ## Perfomance (show me the money!)
27
+
28
+ In a real Rails app, I benchmarked `Tips.all.to_json` with the different
29
+ encoders. On average, YagniJsonEncoder is ~2x as fast. However, you could
30
+ see bigger gains if you models are text-heavy.
31
+
32
+ ```
33
+ Calculating -------------------------------------
34
+ YagniJsonEncoder 10.000 i/100ms
35
+ JSONGemEncoder 5.000 i/100ms
36
+ -------------------------------------------------
37
+ YagniJsonEncoder 105.536 (± 6.6%) i/s - 530.000
38
+ JSONGemEncoder 50.605 (± 4.0%) i/s - 255.000
39
+
40
+ Comparison:
41
+ YagniJsonEncoder: 105.5 i/s
42
+ JSONGemEncoder: 50.6 i/s - 2.09x slower
43
+ ```
44
+
45
+
46
+ ## Installation
47
+
48
+ Just add this line to your application's Gemfile:
49
+
50
+ ```ruby
51
+ gem 'yagni_json_encoder'
52
+ ```
53
+
54
+ And then execute:
55
+
56
+ $ bundle
57
+
58
+ Or install it yourself as:
59
+
60
+ $ gem install yagni_json_encoder
61
+
62
+
63
+ ## Contributing
64
+
65
+ Bug reports and pull requests are welcome on GitHub at
66
+ https://github.com/ianks/yagni_json_encoder.
@@ -0,0 +1,10 @@
1
+ require 'yagni_json_encoder'
2
+
3
+ module ActiveSupport
4
+ self.json_encoder = YagniJsonEncoder
5
+
6
+ def self.escape_html_entities_in_json=(*_args)
7
+ fail StandardError,
8
+ 'escape_html_entities_in_json is not supported in YagniJsonEncoder'
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ require 'oj'
2
+
3
+ class YagniJsonEncoder
4
+ attr_reader :options
5
+
6
+ def initialize(options = nil)
7
+ @options = options || {}
8
+ end
9
+
10
+ def encode(value)
11
+ Oj.dump value.as_json(options.dup),
12
+ mode: :compat,
13
+ quirks_mode: true
14
+ end
15
+ end
16
+
17
+ require 'activesupport/json_encoder'
@@ -0,0 +1,453 @@
1
+ require 'active_support/json'
2
+ require 'active_support/time'
3
+ require 'encoding_test_cases'
4
+ require 'securerandom'
5
+ require 'test_helper'
6
+ require 'time_zone_test_helpers'
7
+
8
+ require 'yagni_json_encoder'
9
+
10
+ class TestJSONEncoding < ActiveSupport::TestCase
11
+ include TimeZoneTestHelpers
12
+
13
+ def sorted_json(json)
14
+ return json unless json =~ /^\{.*\}$/
15
+ '{' + json[1..-2].split(',').sort.join(',') + '}'
16
+ end
17
+
18
+ JSONTest::EncodingTestCases.constants.each do |class_tests|
19
+ define_method("test_#{class_tests[0..-6].underscore}") do
20
+ begin
21
+ prev = ActiveSupport.use_standard_json_time_format
22
+
23
+ ActiveSupport.use_standard_json_time_format = class_tests =~ /^Standard/
24
+ JSONTest::EncodingTestCases.const_get(class_tests).each do |pair|
25
+ assert_equal pair.last, sorted_json(ActiveSupport::JSON.encode(pair.first))
26
+ end
27
+ ensure
28
+ ActiveSupport.use_standard_json_time_format = prev
29
+ end
30
+ end
31
+ end
32
+
33
+ def test_yagni_json_encoder_loaded
34
+ assert_equal ActiveSupport.json_encoder, YagniJsonEncoder
35
+ end
36
+
37
+ def test_process_status
38
+ message = "https://github.com/rubinius/rubinius/issues/3334"
39
+ skip message if RUBY_ENGINE == 'rbx'
40
+
41
+ # There doesn't seem to be a good way to get a handle on a Process::Status object without actually
42
+ # creating a child process, hence this to populate $?
43
+ system("not_a_real_program_#{SecureRandom.hex}")
44
+ assert_equal %({"exitstatus":#{$?.exitstatus},"pid":#{$?.pid}}), ActiveSupport::JSON.encode($?)
45
+ end
46
+
47
+ def test_hash_encoding
48
+ assert_equal %({\"a\":\"b\"}), ActiveSupport::JSON.encode(:a => :b)
49
+ assert_equal %({\"a\":1}), ActiveSupport::JSON.encode('a' => 1)
50
+ assert_equal %({\"a\":[1,2]}), ActiveSupport::JSON.encode('a' => [1,2])
51
+ assert_equal %({"1":2}), ActiveSupport::JSON.encode(1 => 2)
52
+
53
+ assert_equal %({\"a\":\"b\",\"c\":\"d\"}), sorted_json(ActiveSupport::JSON.encode(:a => :b, :c => :d))
54
+ end
55
+
56
+ def test_escape_html_entities_in_json_fails
57
+ assert_raise do
58
+ ActiveSupport.escape_html_entities_in_json = true
59
+ end
60
+ end
61
+
62
+ def test_hash_keys_encoding
63
+ assert_equal "{\"<>\":\"<>\"}", ActiveSupport::JSON.encode("<>" => "<>")
64
+ end
65
+
66
+ def test_utf8_string_encoded_properly
67
+ result = ActiveSupport::JSON.encode('€2.99')
68
+ assert_equal '"€2.99"', result
69
+ assert_equal(Encoding::UTF_8, result.encoding)
70
+
71
+ result = ActiveSupport::JSON.encode('✎☺')
72
+ assert_equal '"✎☺"', result
73
+ assert_equal(Encoding::UTF_8, result.encoding)
74
+ end
75
+
76
+ def test_non_utf8_string_transcodes
77
+ skip
78
+ s = '二'.encode('Shift_JIS')
79
+ result = ActiveSupport::JSON.encode(s)
80
+ assert_equal '"二"', result
81
+ assert_equal Encoding::UTF_8, result.encoding
82
+ end
83
+
84
+ def test_wide_utf8_chars
85
+ w = '𠜎'
86
+ result = ActiveSupport::JSON.encode(w)
87
+ assert_equal '"𠜎"', result
88
+ end
89
+
90
+ def test_wide_utf8_roundtrip
91
+ hash = { string: "𐒑" }
92
+ json = ActiveSupport::JSON.encode(hash)
93
+ decoded_hash = ActiveSupport::JSON.decode(json)
94
+ assert_equal "𐒑", decoded_hash['string']
95
+ end
96
+
97
+ def test_hash_key_identifiers_are_always_quoted
98
+ values = {0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B"}
99
+ assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values))
100
+ end
101
+
102
+ def test_hash_should_allow_key_filtering_with_only
103
+ assert_equal %({"a":1}), ActiveSupport::JSON.encode({'a' => 1, :b => 2, :c => 3}, :only => 'a')
104
+ end
105
+
106
+ def test_hash_should_allow_key_filtering_with_except
107
+ assert_equal %({"b":2}), ActiveSupport::JSON.encode({'foo' => 'bar', :b => 2, :c => 3}, :except => ['foo', :c])
108
+ end
109
+
110
+ def test_time_to_json_includes_local_offset
111
+ with_standard_json_time_format(true) do
112
+ with_env_tz 'US/Eastern' do
113
+ assert_equal %("2005-02-01T15:15:10.000-05:00"), ActiveSupport::JSON.encode(Time.local(2005,2,1,15,15,10))
114
+ end
115
+ end
116
+ end
117
+
118
+ def test_hash_with_time_to_json
119
+ with_standard_json_time_format(false) do
120
+ assert_equal '{"time":"2009/01/01 00:00:00 +0000"}', { :time => Time.utc(2009) }.to_json
121
+ end
122
+ end
123
+
124
+ def test_nested_hash_with_float
125
+ assert_nothing_raised do
126
+ hash = {
127
+ "CHI" => {
128
+ :display_name => "chicago",
129
+ :latitude => 123.234
130
+ }
131
+ }
132
+ ActiveSupport::JSON.encode(hash)
133
+ end
134
+ end
135
+
136
+ def test_hash_like_with_options
137
+ h = JSONTest::Hashlike.new
138
+ json = h.to_json :only => [:foo]
139
+
140
+ assert_equal({"foo"=>"hello"}, JSON.parse(json))
141
+ end
142
+
143
+ def test_object_to_json_with_options
144
+ obj = Object.new
145
+ obj.instance_variable_set :@foo, "hello"
146
+ obj.instance_variable_set :@bar, "world"
147
+ json = obj.to_json :only => ["foo"]
148
+
149
+ assert_equal({"foo"=>"hello"}, JSON.parse(json))
150
+ end
151
+
152
+ def test_struct_to_json_with_options
153
+ struct = Struct.new(:foo, :bar).new
154
+ struct.foo = "hello"
155
+ struct.bar = "world"
156
+ json = struct.to_json :only => [:foo]
157
+
158
+ assert_equal({"foo"=>"hello"}, JSON.parse(json))
159
+ end
160
+
161
+ def test_hash_should_pass_encoding_options_to_children_in_as_json
162
+ person = {
163
+ :name => 'John',
164
+ :address => {
165
+ :city => 'London',
166
+ :country => 'UK'
167
+ }
168
+ }
169
+ json = person.as_json :only => [:address, :city]
170
+
171
+ assert_equal({ 'address' => { 'city' => 'London' }}, json)
172
+ end
173
+
174
+ def test_hash_should_pass_encoding_options_to_children_in_to_json
175
+ person = {
176
+ :name => 'John',
177
+ :address => {
178
+ :city => 'London',
179
+ :country => 'UK'
180
+ }
181
+ }
182
+ json = person.to_json :only => [:address, :city]
183
+
184
+ assert_equal(%({"address":{"city":"London"}}), json)
185
+ end
186
+
187
+ def test_array_should_pass_encoding_options_to_children_in_as_json
188
+ people = [
189
+ { :name => 'John', :address => { :city => 'London', :country => 'UK' }},
190
+ { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }}
191
+ ]
192
+ json = people.as_json :only => [:address, :city]
193
+ expected = [
194
+ { 'address' => { 'city' => 'London' }},
195
+ { 'address' => { 'city' => 'Paris' }}
196
+ ]
197
+
198
+ assert_equal(expected, json)
199
+ end
200
+
201
+ def test_array_should_pass_encoding_options_to_children_in_to_json
202
+ people = [
203
+ { :name => 'John', :address => { :city => 'London', :country => 'UK' }},
204
+ { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }}
205
+ ]
206
+ json = people.to_json :only => [:address, :city]
207
+
208
+ assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json)
209
+ end
210
+
211
+ People = Class.new(BasicObject) do
212
+ include Enumerable
213
+ def initialize()
214
+ @people = [
215
+ { :name => 'John', :address => { :city => 'London', :country => 'UK' }},
216
+ { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }}
217
+ ]
218
+ end
219
+ def each(*, &blk)
220
+ @people.each do |p|
221
+ yield p if blk
222
+ p
223
+ end.each
224
+ end
225
+ end
226
+
227
+ def test_enumerable_should_generate_json_with_as_json
228
+ json = People.new.as_json :only => [:address, :city]
229
+ expected = [
230
+ { 'address' => { 'city' => 'London' }},
231
+ { 'address' => { 'city' => 'Paris' }}
232
+ ]
233
+
234
+ assert_equal(expected, json)
235
+ end
236
+
237
+ def test_enumerable_should_generate_json_with_to_json
238
+ json = People.new.to_json :only => [:address, :city]
239
+ assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json)
240
+ end
241
+
242
+ def test_enumerable_should_pass_encoding_options_to_children_in_as_json
243
+ json = People.new.each.as_json :only => [:address, :city]
244
+ expected = [
245
+ { 'address' => { 'city' => 'London' }},
246
+ { 'address' => { 'city' => 'Paris' }}
247
+ ]
248
+
249
+ assert_equal(expected, json)
250
+ end
251
+
252
+ def test_enumerable_should_pass_encoding_options_to_children_in_to_json
253
+ json = People.new.each.to_json :only => [:address, :city]
254
+
255
+ assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json)
256
+ end
257
+
258
+ class CustomWithOptions
259
+ attr_accessor :foo, :bar
260
+
261
+ def as_json(options={})
262
+ options[:only] = %w(foo bar)
263
+ super(options)
264
+ end
265
+ end
266
+
267
+ def test_hash_to_json_should_not_keep_options_around
268
+ f = CustomWithOptions.new
269
+ f.foo = "hello"
270
+ f.bar = "world"
271
+
272
+ hash = {"foo" => f, "other_hash" => {"foo" => "other_foo", "test" => "other_test"}}
273
+ assert_equal({"foo"=>{"foo"=>"hello","bar"=>"world"},
274
+ "other_hash" => {"foo"=>"other_foo","test"=>"other_test"}}, ActiveSupport::JSON.decode(hash.to_json))
275
+ end
276
+
277
+ def test_array_to_json_should_not_keep_options_around
278
+ f = CustomWithOptions.new
279
+ f.foo = "hello"
280
+ f.bar = "world"
281
+
282
+ array = [f, {"foo" => "other_foo", "test" => "other_test"}]
283
+ assert_equal([{"foo"=>"hello","bar"=>"world"},
284
+ {"foo"=>"other_foo","test"=>"other_test"}], ActiveSupport::JSON.decode(array.to_json))
285
+ end
286
+
287
+ class OptionsTest
288
+ def as_json(options = :default)
289
+ options
290
+ end
291
+ end
292
+
293
+ def test_hash_as_json_without_options
294
+ json = { foo: OptionsTest.new }.as_json
295
+ assert_equal({"foo" => :default}, json)
296
+ end
297
+
298
+ def test_array_as_json_without_options
299
+ json = [ OptionsTest.new ].as_json
300
+ assert_equal([:default], json)
301
+ end
302
+
303
+ def test_struct_encoding
304
+ Struct.new('UserNameAndEmail', :name, :email)
305
+ Struct.new('UserNameAndDate', :name, :date)
306
+ Struct.new('Custom', :name, :sub)
307
+ user_email = Struct::UserNameAndEmail.new 'David', 'sample@example.com'
308
+ user_birthday = Struct::UserNameAndDate.new 'David', Date.new(2010, 01, 01)
309
+ custom = Struct::Custom.new 'David', user_birthday
310
+
311
+
312
+ json_strings = ""
313
+ json_string_and_date = ""
314
+ json_custom = ""
315
+
316
+ assert_nothing_raised do
317
+ json_strings = user_email.to_json
318
+ json_string_and_date = user_birthday.to_json
319
+ json_custom = custom.to_json
320
+ end
321
+
322
+ assert_equal({"name" => "David",
323
+ "sub" => {
324
+ "name" => "David",
325
+ "date" => "2010-01-01" }}, ActiveSupport::JSON.decode(json_custom))
326
+
327
+ assert_equal({"name" => "David", "email" => "sample@example.com"},
328
+ ActiveSupport::JSON.decode(json_strings))
329
+
330
+ assert_equal({"name" => "David", "date" => "2010-01-01"},
331
+ ActiveSupport::JSON.decode(json_string_and_date))
332
+ end
333
+
334
+ def test_nil_true_and_false_represented_as_themselves
335
+ assert_equal nil, nil.as_json
336
+ assert_equal true, true.as_json
337
+ assert_equal false, false.as_json
338
+ end
339
+
340
+ class HashWithAsJson < Hash
341
+ attr_accessor :as_json_called
342
+
343
+ def initialize(*)
344
+ super
345
+ end
346
+
347
+ def as_json(options={})
348
+ @as_json_called = true
349
+ super
350
+ end
351
+ end
352
+
353
+ def test_json_gem_dump_by_passing_active_support_encoder
354
+ h = HashWithAsJson.new
355
+ h[:foo] = "hello"
356
+ h[:bar] = "world"
357
+
358
+ assert_equal %({"foo":"hello","bar":"world"}), JSON.dump(h)
359
+ assert_nil h.as_json_called
360
+ end
361
+
362
+ def test_json_gem_generate_by_passing_active_support_encoder
363
+ h = HashWithAsJson.new
364
+ h[:foo] = "hello"
365
+ h[:bar] = "world"
366
+
367
+ assert_equal %({"foo":"hello","bar":"world"}), JSON.generate(h)
368
+ assert_nil h.as_json_called
369
+ end
370
+
371
+ def test_json_gem_pretty_generate_by_passing_active_support_encoder
372
+ h = HashWithAsJson.new
373
+ h[:foo] = "hello"
374
+ h[:bar] = "world"
375
+
376
+ assert_equal <<EXPECTED.chomp, JSON.pretty_generate(h)
377
+ {
378
+ "foo": "hello",
379
+ "bar": "world"
380
+ }
381
+ EXPECTED
382
+ assert_nil h.as_json_called
383
+ end
384
+
385
+ def test_twz_to_json_with_use_standard_json_time_format_config_set_to_false
386
+ with_standard_json_time_format(false) do
387
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
388
+ time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone)
389
+ assert_equal "\"1999/12/31 19:00:00 -0500\"", ActiveSupport::JSON.encode(time)
390
+ end
391
+ end
392
+
393
+ def test_twz_to_json_with_use_standard_json_time_format_config_set_to_true
394
+ with_standard_json_time_format(true) do
395
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
396
+ time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone)
397
+ assert_equal "\"1999-12-31T19:00:00.000-05:00\"", ActiveSupport::JSON.encode(time)
398
+ end
399
+ end
400
+
401
+ def test_twz_to_json_with_custom_time_precision
402
+ with_standard_json_time_format(true) do
403
+ with_time_precision(0) do
404
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
405
+ time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone)
406
+ assert_equal "\"1999-12-31T19:00:00-05:00\"", ActiveSupport::JSON.encode(time)
407
+ end
408
+ end
409
+ end
410
+
411
+ def test_time_to_json_with_custom_time_precision
412
+ with_standard_json_time_format(true) do
413
+ with_time_precision(0) do
414
+ assert_equal "\"2000-01-01T00:00:00Z\"", ActiveSupport::JSON.encode(Time.utc(2000))
415
+ end
416
+ end
417
+ end
418
+
419
+ def test_datetime_to_json_with_custom_time_precision
420
+ with_standard_json_time_format(true) do
421
+ with_time_precision(0) do
422
+ assert_equal "\"2000-01-01T00:00:00+00:00\"", ActiveSupport::JSON.encode(DateTime.new(2000))
423
+ end
424
+ end
425
+ end
426
+
427
+ def test_twz_to_json_when_wrapping_a_date_time
428
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
429
+ time = ActiveSupport::TimeWithZone.new(DateTime.new(2000), zone)
430
+ assert_equal '"1999-12-31T19:00:00.000-05:00"', ActiveSupport::JSON.encode(time)
431
+ end
432
+
433
+ protected
434
+
435
+ def object_keys(json_object)
436
+ json_object[1..-2].scan(/([^{}:,\s]+):/).flatten.sort
437
+ end
438
+
439
+ def with_standard_json_time_format(boolean = true)
440
+ old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, boolean
441
+ yield
442
+ ensure
443
+ ActiveSupport.use_standard_json_time_format = old
444
+ end
445
+
446
+ def with_time_precision(value)
447
+ old_value = ActiveSupport::JSON::Encoding.time_precision
448
+ ActiveSupport::JSON::Encoding.time_precision = value
449
+ yield
450
+ ensure
451
+ ActiveSupport::JSON::Encoding.time_precision = old_value
452
+ end
453
+ end
@@ -0,0 +1,84 @@
1
+ require 'bigdecimal'
2
+
3
+ module JSONTest
4
+ class Foo
5
+ def initialize(a, b)
6
+ @a, @b = a, b
7
+ end
8
+ end
9
+
10
+ class Hashlike
11
+ def to_hash
12
+ { :foo => "hello", :bar => "world" }
13
+ end
14
+ end
15
+
16
+ class Custom
17
+ def initialize(serialized)
18
+ @serialized = serialized
19
+ end
20
+
21
+ def as_json(options = nil)
22
+ @serialized
23
+ end
24
+ end
25
+
26
+ class MyStruct < Struct.new(:name, :value)
27
+ def initialize(*)
28
+ @unused = "unused instance variable"
29
+ super
30
+ end
31
+ end
32
+
33
+ module EncodingTestCases
34
+ TrueTests = [[ true, %(true) ]]
35
+ FalseTests = [[ false, %(false) ]]
36
+ NilTests = [[ nil, %(null) ]]
37
+ NumericTests = [[ 1, %(1) ],
38
+ [ 2.5, %(2.5) ],
39
+ [ 0.0/0.0, %(null) ],
40
+ [ 1.0/0.0, %(null) ],
41
+ [ -1.0/0.0, %(null) ],
42
+ [ BigDecimal('0.0')/BigDecimal('0.0'), %(null) ],
43
+ [ BigDecimal('2.5'), %("#{BigDecimal('2.5')}") ]]
44
+
45
+ StringTests = [[ 'http://test.host/posts/1', %("http://test.host/posts/1")]]
46
+
47
+ ArrayTests = [[ ['a', 'b', 'c'], %([\"a\",\"b\",\"c\"]) ],
48
+ [ [1, 'a', :b, nil, false], %([1,\"a\",\"b\",null,false]) ]]
49
+
50
+ HashTests = [[ {foo: "bar"}, %({\"foo\":\"bar\"}) ],
51
+ [ {1 => 1, 2 => 'a', 3 => :b, 4 => nil, 5 => false}, %({\"1\":1,\"2\":\"a\",\"3\":\"b\",\"4\":null,\"5\":false}) ]]
52
+
53
+ RangeTests = [[ 1..2, %("1..2")],
54
+ [ 1...2, %("1...2")],
55
+ [ 1.5..2.5, %("1.5..2.5")]]
56
+
57
+ SymbolTests = [[ :a, %("a") ],
58
+ [ :this, %("this") ],
59
+ [ :"a b", %("a b") ]]
60
+
61
+ ObjectTests = [[ Foo.new(1, 2), %({\"a\":1,\"b\":2}) ]]
62
+ HashlikeTests = [[ Hashlike.new, %({\"bar\":\"world\",\"foo\":\"hello\"}) ]]
63
+ StructTests = [[ MyStruct.new(:foo, "bar"), %({\"name\":\"foo\",\"value\":\"bar\"}) ],
64
+ [ MyStruct.new(nil, nil), %({\"name\":null,\"value\":null}) ]]
65
+ CustomTests = [[ Custom.new("custom"), '"custom"' ],
66
+ [ Custom.new(nil), 'null' ],
67
+ [ Custom.new(:a), '"a"' ],
68
+ [ Custom.new([ :foo, "bar" ]), '["foo","bar"]' ],
69
+ [ Custom.new({ :foo => "hello", :bar => "world" }), '{"bar":"world","foo":"hello"}' ],
70
+ [ Custom.new(Hashlike.new), '{"bar":"world","foo":"hello"}' ],
71
+ [ Custom.new(Custom.new(Custom.new(:a))), '"a"' ]]
72
+
73
+ RegexpTests = [[ /^a/, '"(?-mix:^a)"' ], [/^\w{1,2}[a-z]+/ix, '"(?ix-m:^\\\\w{1,2}[a-z]+)"']]
74
+
75
+ DateTests = [[ Date.new(2005,2,1), %("2005/02/01") ]]
76
+ TimeTests = [[ Time.utc(2005,2,1,15,15,10), %("2005/02/01 15:15:10 +0000") ]]
77
+ DateTimeTests = [[ DateTime.civil(2005,2,1,15,15,10), %("2005/02/01 15:15:10 +0000") ]]
78
+
79
+ StandardDateTests = [[ Date.new(2005,2,1), %("2005-02-01") ]]
80
+ StandardTimeTests = [[ Time.utc(2005,2,1,15,15,10), %("2005-02-01T15:15:10.000Z") ]]
81
+ StandardDateTimeTests = [[ DateTime.civil(2005,2,1,15,15,10), %("2005-02-01T15:15:10.000+00:00") ]]
82
+ StandardStringTests = [[ 'this is the <string>', %("this is the <string>")]]
83
+ end
84
+ end
@@ -0,0 +1,17 @@
1
+ require 'active_support/core_ext/kernel/reporting'
2
+
3
+ silence_warnings do
4
+ Encoding.default_internal = "UTF-8"
5
+ Encoding.default_external = "UTF-8"
6
+ end
7
+
8
+ require 'bundler/setup'
9
+ require 'minitest/autorun'
10
+ require 'active_support'
11
+ require 'active_support/test_case'
12
+ require 'active_support/testing/autorun'
13
+
14
+ Thread.abort_on_exception = true
15
+
16
+ # Show backtraces for deprecated behavior for quicker cleanup.
17
+ ActiveSupport::Deprecation.debug = true
@@ -0,0 +1,16 @@
1
+ module TimeZoneTestHelpers
2
+ def with_tz_default(tz = nil)
3
+ old_tz = Time.zone
4
+ Time.zone = tz
5
+ yield
6
+ ensure
7
+ Time.zone = old_tz
8
+ end
9
+
10
+ def with_env_tz(new_tz = 'US/Eastern')
11
+ old_tz, ENV['TZ'] = ENV['TZ'], new_tz
12
+ yield
13
+ ensure
14
+ old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
15
+ end
16
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yagni_json_encoder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Ian Ker-Seymer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-02-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: oj
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.14'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.14'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 4.1.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 4.1.0
55
+ description:
56
+ email:
57
+ - i.kerseymer@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - lib/activesupport/json_encoder.rb
65
+ - lib/yagni_json_encoder.rb
66
+ - test/encoding_test.rb
67
+ - test/encoding_test_cases.rb
68
+ - test/test_helper.rb
69
+ - test/time_zone_test_helpers.rb
70
+ homepage: https://github.com/ianks/yagni_json_encoder
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.4.5.1
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: "~2x faster JSON encoder for Rails"
94
+ test_files:
95
+ - test/time_zone_test_helpers.rb
96
+ - test/encoding_test_cases.rb
97
+ - test/test_helper.rb
98
+ - test/encoding_test.rb
99
+ has_rdoc: