json_parser 0.1.0 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 099520dbb41927983f35746666f093785c9e3e4a
4
- data.tar.gz: c6952b7b2b128a298e4e54210760a58cfb3e5238
3
+ metadata.gz: aa3db49e4e788b1d0842fc1a76177a420dddea7a
4
+ data.tar.gz: 2e53eee8b60b49d2c789adc5da2aa415b83528c9
5
5
  SHA512:
6
- metadata.gz: 4297d6a7cf28e3295ecc7a22e4573368774583970447a90803915a9334996a9755dbd07a80550f2108b7d8cf9c74d7eb821f1fa5faabc0d72f90f07d6c71c36e
7
- data.tar.gz: 08e0851107751b1926997769d018a9c2714c68c3674bb1805aabe80b0d1c37a318e4d39d3145e59edafd04c77838ec06d3b9f8ec2c6cc08710db99ff17df7835
6
+ metadata.gz: c501a429649f8578db081111b1db7d07475f31645764277aed8f02ec834cece16b739fe5f5769ec41dfe46c02cd58db7e147fcf361a82114f616fa60b04c7264
7
+ data.tar.gz: bdf68e4a5fb504178908b51bbc992028b0442c4f9009db32c1e85c6f9de29cc13aeb676529e07c9937691708b150364a094dfc9316e959b4c6807cafc5520a56
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile CHANGED
@@ -3,6 +3,6 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  group :test do
6
- gem 'safe_attribute_assignment', '0.0.3', git: 'git@github.com:Bidu/safe_attribute_assignment.git'
6
+ gem 'safe_attribute_assignment', '0.0.3'
7
7
  end
8
8
 
@@ -1,14 +1,7 @@
1
- GIT
2
- remote: git@github.com:Bidu/safe_attribute_assignment.git
3
- revision: 7ccb0c0f56a1c5f8d3f844144d7b4148069bc2a0
4
- specs:
5
- safe_attribute_assignment (0.0.3)
6
- activesupport
7
-
8
1
  PATH
9
2
  remote: .
10
3
  specs:
11
- json_parser (0.1.0)
4
+ json_parser (1.0.0)
12
5
  activesupport
13
6
 
14
7
  GEM
@@ -35,6 +28,8 @@ GEM
35
28
  rspec-expectations (2.99.2)
36
29
  diff-lcs (>= 1.1.3, < 2.0)
37
30
  rspec-mocks (2.99.3)
31
+ safe_attribute_assignment (0.0.3)
32
+ activesupport
38
33
  simplecov (0.9.1)
39
34
  docile (~> 1.1.0)
40
35
  multi_json (~> 1.0)
@@ -52,5 +47,5 @@ DEPENDENCIES
52
47
  json_parser!
53
48
  rake
54
49
  rspec (~> 2.14)
55
- safe_attribute_assignment (= 0.0.3)!
50
+ safe_attribute_assignment (= 0.0.3)
56
51
  simplecov
@@ -0,0 +1,9 @@
1
+ module OptionsParser
2
+ extend ActiveSupport::Concern
3
+
4
+ attr_reader :options
5
+
6
+ def options_object
7
+ @options_object ||= OpenStruct.new options
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ module TypeCast
2
+ extend ActiveSupport::Concern
3
+
4
+ def to_integer(value)
5
+ value.to_i if value.present?
6
+ end
7
+
8
+ def to_string(value)
9
+ value.to_s
10
+ end
11
+
12
+ def to_float(value)
13
+ value.to_f if value.present?
14
+ end
15
+ end
@@ -4,7 +4,12 @@ require 'active_support/all'
4
4
  module JsonParser
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ require 'concerns/type_cast'
8
+ require 'concerns/options_parser'
7
9
  require 'json_parser/version'
10
+ require 'json_parser/crawler'
11
+ require 'json_parser/wrapper'
8
12
  require 'json_parser/fetcher'
9
13
  require 'json_parser/class_methods'
14
+ require 'json_parser/class_methods/builder'
10
15
  end
@@ -1,4 +1,5 @@
1
1
  module JsonParser::ClassMethods
2
+
2
3
  def json_parse(*attr_names)
3
4
  options = {
4
5
  path: nil,
@@ -7,97 +8,13 @@ module JsonParser::ClassMethods
7
8
  cached: false,
8
9
  class: nil,
9
10
  compact: false,
10
- after: nil,
11
- case: :lower_camel
11
+ flatten: false,
12
+ after: false,
13
+ case: :lower_camel,
14
+ type: :none
12
15
  }.merge(attr_names.extract_options!)
13
16
 
14
17
  builder = Builder.new(attr_names, self, options)
15
18
  builder.build
16
19
  end
17
-
18
- class Builder
19
- attr_reader :attr_names, :options, :methods_def
20
-
21
- def initialize(attr_names, instance, options)
22
- @attr_names = attr_names
23
- @instance = instance
24
- @options = options
25
- @methods_def = []
26
- init
27
- end
28
-
29
- def build
30
- methods_def.each do |method_def|
31
- @instance.module_eval(method_def, __FILE__, __LINE__ + 1)
32
- end
33
- end
34
-
35
- private
36
-
37
- def init
38
- attr_names.each do |attr|
39
- add_attr(attr)
40
- end
41
- end
42
-
43
- def path
44
- options[:path]
45
- end
46
-
47
- def json_name
48
- options[:json]
49
- end
50
-
51
- def full_path(attribute)
52
- options[:full_path] || [path, attribute].compact.join('.')
53
- end
54
-
55
- def cached
56
- options[:cached]
57
- end
58
-
59
- def clazz
60
- options[:class]
61
- end
62
-
63
- def compact
64
- options[:compact]
65
- end
66
-
67
- def after
68
- options[:after] ? ":#{options[:after]}" : false
69
- end
70
-
71
- def case_type
72
- options[:case]
73
- end
74
-
75
- def add_attr(attribute)
76
- @methods_def << <<-CODE
77
- def #{attribute}
78
- #{cached ? cached_fetcher(attribute) : attr_fetcher(attribute)}
79
- end
80
- CODE
81
- end
82
-
83
- def attr_fetcher(attribute)
84
- <<-CODE
85
- JsonParser::Fetcher.new(
86
- #{json_name}, '#{full_path(attribute)}', {
87
- instance: self,
88
- class: #{clazz || 'nil'},
89
- compact: #{compact || 'false'},
90
- after: #{after},
91
- case_type: :#{case_type}
92
- }
93
- ).fetch
94
- CODE
95
- end
96
-
97
- def cached_fetcher(attribute)
98
- <<-CODE
99
- @#{attribute} ||= #{attr_fetcher(attribute)}
100
- CODE
101
- end
102
- end
103
20
  end
@@ -0,0 +1,74 @@
1
+ class JsonParser::ClassMethods::Builder
2
+ include OptionsParser
3
+
4
+ attr_reader :attr_names, :methods_def
5
+
6
+ delegate :path, :cached, :compact, :type, :after, to: :options_object
7
+
8
+ def initialize(attr_names, instance, options)
9
+ @attr_names = attr_names
10
+ @instance = instance
11
+ @options = options
12
+ @methods_def = []
13
+ init
14
+ end
15
+
16
+ def build
17
+ methods_def.each do |method_def|
18
+ @instance.module_eval(method_def, __FILE__, __LINE__ + 1)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def init
25
+ attr_names.each do |attr|
26
+ add_attr(attr)
27
+ end
28
+ end
29
+
30
+ def json_name
31
+ options[:json]
32
+ end
33
+
34
+ def full_path(attribute)
35
+ options[:full_path] || [path, attribute].compact.join('.')
36
+ end
37
+
38
+ def clazz
39
+ options[:class]
40
+ end
41
+
42
+ def case_type
43
+ options[:case]
44
+ end
45
+
46
+ def fetcher_options
47
+ options.slice(:compact, :after, :type, :flatten).merge({
48
+ clazz: clazz,
49
+ case_type: case_type
50
+ })
51
+ end
52
+
53
+ def add_attr(attribute)
54
+ @methods_def << <<-CODE
55
+ def #{attribute}
56
+ #{cached ? cached_fetcher(attribute) : attr_fetcher(attribute)}
57
+ end
58
+ CODE
59
+ end
60
+
61
+ def attr_fetcher(attribute)
62
+ <<-CODE
63
+ JsonParser::Fetcher.new(
64
+ #{json_name}, '#{full_path(attribute)}', self, #{fetcher_options}
65
+ ).fetch
66
+ CODE
67
+ end
68
+
69
+ def cached_fetcher(attribute)
70
+ <<-CODE
71
+ @#{attribute} ||= #{attr_fetcher(attribute)}
72
+ CODE
73
+ end
74
+ end
@@ -0,0 +1,53 @@
1
+ class JsonParser::Crawler
2
+ include OptionsParser
3
+
4
+ attr_reader :post_process, :path
5
+
6
+ delegate :case_type, :compact, to: :options_object
7
+
8
+ def initialize(path, options = {}, &block)
9
+ @options = options
10
+ @path = path.map { |p| change_case(p) }
11
+ @post_process = block
12
+ end
13
+
14
+ def crawl(json, index = 0)
15
+ return nil if json.nil?
16
+ return wrap(json) if is_ended?(index)
17
+ return crawl_array(json, index) if json.is_a? Array
18
+
19
+ crawl(fetch(json, index), index + 1)
20
+ end
21
+
22
+ private
23
+
24
+ def fetch(json, index)
25
+ key = path[index]
26
+ json.key?(key) ? json[key] : json[key.to_sym]
27
+ end
28
+
29
+ def is_ended?(index)
30
+ index >= path.size
31
+ end
32
+
33
+ def wrap(json)
34
+ post_process.call(json)
35
+ end
36
+
37
+ def change_case(key)
38
+ case case_type
39
+ when :lower_camel
40
+ key.camelize(:lower)
41
+ when :upper_camel
42
+ key.camelize(:upper)
43
+ when :snake
44
+ key.underscore
45
+ end
46
+ end
47
+
48
+ def crawl_array(array, index)
49
+ array.map { |j| crawl(j, index) }.tap do |a|
50
+ a.compact! if compact
51
+ end
52
+ end
53
+ end
@@ -1,72 +1,51 @@
1
1
  class JsonParser::Fetcher
2
- attr_reader :path, :json, :options
2
+ include OptionsParser
3
3
 
4
- def initialize(json, path, options = {})
4
+ attr_reader :path, :json, :instance
5
+
6
+ delegate :after, :flatten, to: :options_object
7
+ delegate :wrap, to: :wrapper
8
+ delegate :crawl, to: :crawler
9
+
10
+ def initialize(json, path, instance, options = {})
5
11
  @path = path.to_s.split('.')
6
12
  @json = json
13
+ @instance = instance
7
14
  @options = options
8
15
  end
9
16
 
10
17
  def fetch
11
- value = crawl(json, path)
18
+ value = crawl(json)
19
+ value.flatten! if flatten && value.respond_to?(:flatten!)
12
20
  value = instance.send(after, value) if after
13
21
  value
14
22
  end
15
23
 
16
24
  private
17
25
 
18
- def crawl(json, path)
19
- return nil if json.nil?
20
- return wrap(json) if path.empty?
21
- return crawl_array(json, path) if json.is_a? Array
22
-
23
- key = change_case(path[0])
24
- value = json.key?(key) ? json[key] : json[key.to_sym]
25
- crawl(value, path[1,path.size])
26
- end
27
-
28
- def change_case(key)
29
- case case_type
30
- when :lower_camel
31
- key.camelize(:lower)
32
- when :upper_camel
33
- key.camelize(:upper)
34
- when :snake
35
- key.underscore
36
- end
26
+ def crawler
27
+ @crawler ||= buidl_crawler
37
28
  end
38
29
 
39
- def crawl_array(array, path)
40
- array.map { |j| crawl(j, path) }.tap do |a|
41
- a.compact! if compact
30
+ def buidl_crawler
31
+ JsonParser::Crawler.new(path, crawler_options) do |value|
32
+ wrap(value)
42
33
  end
43
34
  end
44
35
 
45
- def wrap(json)
46
- return json unless clazz
47
- return clazz.new json unless json.is_a? Array
48
- json.map { |v| wrap v }.tap do |j|
49
- j.compact! if compact
50
- end
51
- end
52
-
53
- def clazz
54
- options[:class]
55
- end
56
-
57
- def after
58
- options[:after]
36
+ def crawler_options
37
+ options.slice(:case_type, :compact)
59
38
  end
60
39
 
61
- def instance
62
- options[:instance]
40
+ def wrapper
41
+ @wrapper ||= build_wrapper
63
42
  end
64
43
 
65
- def compact
66
- options[:compact]
44
+ def build_wrapper
45
+ JsonParser::Wrapper.new(wrapper_options)
67
46
  end
68
47
 
69
- def case_type
70
- options[:case_type]
48
+ def wrapper_options
49
+ options.slice(:clazz, :type)
71
50
  end
72
- end
51
+ end
@@ -1,3 +1,3 @@
1
1
  module JsonParser
2
- VERSION = '0.1.0'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -0,0 +1,30 @@
1
+ class JsonParser::Wrapper
2
+ include OptionsParser
3
+ include TypeCast
4
+
5
+ delegate :clazz, :type, to: :options_object
6
+
7
+ def initialize(options = {})
8
+ @options = options
9
+ end
10
+
11
+ def wrap(value)
12
+ return value.map { |v| wrap v } if value.is_a?(Array)
13
+
14
+ value = cast(value) if has_type? && !value.nil?
15
+ return if value.nil?
16
+
17
+ value = clazz.new(value) if clazz
18
+ value
19
+ end
20
+
21
+ private
22
+
23
+ def has_type?
24
+ type.present? && type != :none
25
+ end
26
+
27
+ def cast(value)
28
+ send("to_#{type}", value)
29
+ end
30
+ end
@@ -0,0 +1,161 @@
1
+ require 'spec_helper'
2
+
3
+ describe JsonParser::Crawler do
4
+ let(:subject) do
5
+ described_class.new path, default_options.merge(options), &block
6
+ end
7
+ let(:block) { proc { |v| v } }
8
+ let(:path) { '' }
9
+ let(:default_options) { { case_type: :lower_camel} }
10
+ let(:options) { {} }
11
+ let(:json) { load_json_fixture_file('json_parser.json') }
12
+ let(:value) { subject.crawl(json) }
13
+
14
+ context 'when parsing with a path' do
15
+ let(:path) { %w(user name) }
16
+
17
+ it 'retrieves attribute from base json' do
18
+ expect(value).to eq(json['user']['name'])
19
+ end
20
+ end
21
+
22
+ context 'crawler finds a nil attribute' do
23
+ let(:path) { %w(car model) }
24
+
25
+ it 'returns nil' do
26
+ expect(value).to be_nil
27
+ end
28
+
29
+ it do
30
+ expect { value }.not_to raise_error
31
+ end
32
+ end
33
+
34
+ context 'when json is empty' do
35
+ let(:json) { nil }
36
+ let(:path) { %w(car model) }
37
+
38
+ it 'returns nil' do
39
+ expect(value).to be_nil
40
+ end
41
+
42
+ it do
43
+ expect { value }.not_to raise_error
44
+ end
45
+ end
46
+
47
+ context 'with an snake case path' do
48
+ let(:path) { ['has_money'] }
49
+
50
+ it 'returns camel cased value' do
51
+ expect(value).to eq(json['hasMoney'])
52
+ end
53
+ end
54
+
55
+ context 'when dealing with json inside arrays' do
56
+ let(:path) { %w(animals race species name)}
57
+ let(:expected) do
58
+ ['European squid', 'Macaque monkey', 'Mexican redknee tarantula']
59
+ end
60
+
61
+ it do
62
+ expect(value).to be_a(Array)
63
+ end
64
+
65
+ it 'parses them mapping arrays as sub parse' do
66
+ expect(value).to eq(expected)
67
+ end
68
+
69
+ context 'when there are nil values' do
70
+ context 'with compact option as false' do
71
+ let(:options) { { compact: false } }
72
+ before do
73
+ json["animals"].last['race'] = nil
74
+ end
75
+ let(:expected) do
76
+ ['European squid', 'Macaque monkey', nil]
77
+ end
78
+
79
+ it 'eliminate nil values' do
80
+ expect(value).to eq(expected)
81
+ end
82
+ end
83
+
84
+ context 'with compact option' do
85
+ let(:options) { { compact: true } }
86
+ before do
87
+ json["animals"].last['race'] = nil
88
+ end
89
+ let(:expected) do
90
+ ['European squid', 'Macaque monkey']
91
+ end
92
+
93
+ it 'eliminate nil values' do
94
+ expect(value).to eq(expected)
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ context 'when using a snake case' do
101
+ let(:json) { { snake_cased: 'snake', snakeCased: 'Camel' }.stringify_keys }
102
+ let(:path) { [ 'snake_cased' ] }
103
+ let(:options) { { case_type: :snake } }
104
+
105
+ it 'fetches from snake cased fields' do
106
+ expect(value).to eq('snake')
107
+ end
108
+ end
109
+
110
+ context 'when using a upper camel case' do
111
+ let(:json) { { UpperCase: 'upper', upperCase: 'lower' }.stringify_keys }
112
+ let(:path) { [ 'upper_case' ] }
113
+ let(:options) { { case_type: :upper_camel } }
114
+
115
+ it 'fetches from upper camel cased fields' do
116
+ expect(value).to eq('upper')
117
+ end
118
+ end
119
+
120
+ context 'when using a symbol keys' do
121
+ let(:json) { load_json_fixture_file('json_parser.json').symbolize_keys }
122
+ let(:path) { [ 'id' ] }
123
+
124
+ it 'fetches from symbol keys' do
125
+ expect(value).to eq(json[:id])
126
+ end
127
+
128
+ context 'crawler finds a nil attribute' do
129
+ let(:path) { %w(car model) }
130
+
131
+ it 'returns nil' do
132
+ expect(value).to be_nil
133
+ end
134
+
135
+ it do
136
+ expect { value }.not_to raise_error
137
+ end
138
+ end
139
+ end
140
+
141
+ context 'when using key with false value' do
142
+ let(:path) { ['has_money'] }
143
+ before do
144
+ json['hasMoney'] = false
145
+ end
146
+
147
+ context 'with string keys' do
148
+ it { expect(value).to be_falsey }
149
+ it { expect(value).not_to be_nil }
150
+ end
151
+
152
+ context 'with symbol keys' do
153
+ before do
154
+ json.symbolize_keys!
155
+ end
156
+
157
+ it { expect(value).to be_falsey }
158
+ it { expect(value).not_to be_nil }
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ describe JsonParser::Fetcher do
4
+ class JsonParser::Fetcher::Dummy
5
+ end
6
+
7
+ let(:subject) do
8
+ described_class.new json, path, instance, default_options.merge(options)
9
+ end
10
+ let(:path) { '' }
11
+ let(:default_options) { { case_type: :snake} }
12
+ let(:instance) { JsonParser::Fetcher::Dummy.new }
13
+ let(:json) { load_json_fixture_file('json_parser.json') }
14
+ let(:value) { subject.fetch }
15
+
16
+ context 'when fetching with no options' do
17
+ let(:options) { {} }
18
+ let(:path) { 'id' }
19
+
20
+ it 'retrieves attribute from base json' do
21
+ expect(value).to eq(json['id'])
22
+ end
23
+
24
+ context 'when calling the method twice' do
25
+ before do
26
+ subject.fetch
27
+ end
28
+
29
+ it 'retrieves attribute from base json' do
30
+ expect(value).to eq(json['id'])
31
+ end
32
+ end
33
+
34
+ context 'when changing json value' do
35
+ let!(:old_value) { json['id'] }
36
+ before do
37
+ subject.fetch
38
+ json['id'] = 200
39
+ end
40
+
41
+ it 'retrieves the new value' do
42
+ expect(value).not_to eq(old_value)
43
+ end
44
+ end
45
+ end
46
+
47
+ describe 'flatten options' do
48
+ let(:json) { [[[1,2],[3,4]],[[5,6],[7,8]]] }
49
+
50
+ context 'when flatten option is true' do
51
+ let(:options) { { flatten: true } }
52
+
53
+ it 'returns the fetched value flattened' do
54
+ expect(subject.fetch).to eq((1..8).to_a)
55
+ end
56
+
57
+ context 'when value is not an array' do
58
+ let(:json) { 1 }
59
+
60
+ it 'returns the fetched value flattened' do
61
+ expect(subject.fetch).to eq(1)
62
+ end
63
+ end
64
+ end
65
+
66
+ context 'when flatten option is false' do
67
+ let(:options) { { flatten: false } }
68
+
69
+ it 'returns the fetched value non flattened' do
70
+ expect(subject.fetch).to eq(json)
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,129 @@
1
+ require 'spec_helper'
2
+
3
+ describe JsonParser::Wrapper do
4
+
5
+ class JsonParser::Wrapper::DummyWrapper
6
+ attr_reader :value
7
+ def initialize(value)
8
+ @value = value
9
+ end
10
+ end
11
+
12
+ let(:options) { {} }
13
+ let(:subject) { described_class.new options }
14
+ let(:hash) { { a: 1 } }
15
+
16
+ describe '#wrap' do
17
+ let(:value) { hash }
18
+ let(:result) { subject.wrap(value) }
19
+
20
+ context 'with default options' do
21
+ it 'does not change the json value' do
22
+ expect(result).to eq(value)
23
+ end
24
+
25
+ context 'with an array as value' do
26
+ let(:value) { [hash] }
27
+
28
+ it 'does not change the array' do
29
+ expect(result).to eq(value)
30
+ end
31
+ end
32
+ end
33
+
34
+ context 'with clazz otpion' do
35
+ let(:options) { { clazz: OpenStruct } }
36
+
37
+ it 'creates new instance from given class' do
38
+ expect(result).to be_a(OpenStruct)
39
+ expect(result.a).to eq(hash[:a])
40
+ end
41
+
42
+ context 'with an array as value' do
43
+ let(:value) { [hash] }
44
+
45
+ it 'returns an array of objects of the given class' do
46
+ expect(result).to be_a(Array)
47
+ expect(result.first).to be_a(OpenStruct)
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'with type otpion' do
53
+ let(:type) { :integer }
54
+ let(:value) { '1' }
55
+ let(:options) { { type: type } }
56
+ let(:cast) { result }
57
+
58
+ it_behaves_like 'casts basic types'
59
+
60
+ context 'when processing an array' do
61
+ let(:value) { [1.0] }
62
+ let(:cast) { result.first }
63
+
64
+ it_behaves_like 'casts basic types'
65
+
66
+ it do
67
+ expect(result).to be_a(Array)
68
+ end
69
+ end
70
+
71
+ context 'with nil value' do
72
+ let(:value) { nil }
73
+
74
+ it do
75
+ expect(result).to be_nil
76
+ end
77
+
78
+ context 'when passing clazz parameter' do
79
+ let(:options) { { type: type, clazz: JsonParser::Wrapper::DummyWrapper } }
80
+
81
+ it do
82
+ expect(result).to be_nil
83
+ end
84
+ end
85
+ end
86
+
87
+ context 'with blank value' do
88
+ let(:value) { '' }
89
+
90
+ it_behaves_like 'a result that is type cast', {
91
+ integer: NilClass,
92
+ float: NilClass,
93
+ string: String
94
+ }
95
+
96
+ context 'when passing clazz parameter' do
97
+ let(:options) { { type: type, clazz: JsonParser::Wrapper::DummyWrapper } }
98
+
99
+ it_behaves_like 'a result that is type cast', {
100
+ integer: NilClass,
101
+ float: NilClass,
102
+ string: JsonParser::Wrapper::DummyWrapper
103
+ }
104
+ end
105
+ end
106
+
107
+ context 'when passing clazz parameter' do
108
+ let(:value) { 1 }
109
+ let(:options) { { type: type, clazz: JsonParser::Wrapper::DummyWrapper } }
110
+ let(:cast) { result.value }
111
+
112
+ it_behaves_like 'casts basic types'
113
+
114
+ it 'wraps the result inside the given class' do
115
+ expect(result).to be_a(JsonParser::Wrapper::DummyWrapper)
116
+ end
117
+ end
118
+
119
+ context 'with none for type' do
120
+ let(:type) { :none }
121
+ let(:value) { 1.0 }
122
+
123
+ it 'does not cast the value' do
124
+ expect(result).to eq(value)
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -31,14 +31,11 @@ describe JsonParser do
31
31
 
32
32
  json_parse :id
33
33
  json_parse :name, path: 'user'
34
- json_parse :model, path: 'car'
35
34
  json_parse :father_name, full_path: 'father.name'
36
35
  json_parse :age, cached: true
37
- json_parse :has_money
38
36
  json_parse :house, class: JsonParser::House
39
37
  json_parse :old_house, class: JsonParser::House, cached: true
40
38
  json_parse :games, class: JsonParser::Game
41
- json_parse :species_name, full_path: 'animals.race.species.name', compact: true
42
39
  json_parse :games_filtered, class: JsonParser::Game, after: :filter_games, full_path: 'games'
43
40
 
44
41
  def initialize(json)
@@ -62,27 +59,6 @@ describe JsonParser do
62
59
  it 'retrieves attribute from base json' do
63
60
  expect(value).to eq(json['id'])
64
61
  end
65
-
66
- context 'when calling the method twice' do
67
- before do
68
- dummy.public_send(attribute)
69
- end
70
-
71
- it 'retrieves attribute from base json' do
72
- expect(value).to eq(json['id'])
73
- end
74
- end
75
-
76
- context 'when changing json value' do
77
- let!(:old_value) { json['id'] }
78
- before do
79
- dummy.id
80
- json['id'] = 200
81
- end
82
- it 'retrieves the new value' do
83
- expect(value).not_to eq(old_value)
84
- end
85
- end
86
62
  end
87
63
 
88
64
  context 'when parser is configured with a path' do
@@ -93,31 +69,6 @@ describe JsonParser do
93
69
  end
94
70
  end
95
71
 
96
- context 'parser finds a nil attribute' do
97
- let(:attribute) { :model }
98
-
99
- it 'returns nil' do
100
- expect(value).to be_nil
101
- end
102
-
103
- it do
104
- expect { value }.not_to raise_error
105
- end
106
- end
107
-
108
- context 'when json is instead of empty' do
109
- let(:json) { nil }
110
- let(:attribute) { :model }
111
-
112
- it 'returns nil' do
113
- expect(value).to be_nil
114
- end
115
-
116
- it do
117
- expect { value }.not_to raise_error
118
- end
119
- end
120
-
121
72
  context 'when configuring full path' do
122
73
  let(:attribute) { :father_name }
123
74
 
@@ -139,14 +90,6 @@ describe JsonParser do
139
90
  end
140
91
  end
141
92
 
142
- context 'with an snake case option' do
143
- let(:attribute) { :has_money }
144
-
145
- it 'returns camel cased value' do
146
- expect(value).to eq(json['hasMoney'])
147
- end
148
- end
149
-
150
93
  context 'when wrapping it with a class' do
151
94
  let(:attribute) { :house }
152
95
 
@@ -211,34 +154,6 @@ describe JsonParser do
211
154
  end
212
155
  end
213
156
 
214
- context 'when dealing with json inside arrays' do
215
- let(:attribute) { :species_name }
216
- let(:expected) do
217
- ['European squid', 'Macaque monkey', 'Mexican redknee tarantula']
218
- end
219
-
220
- it do
221
- expect(value).to be_a(Array)
222
- end
223
-
224
- it 'parses them mapping arrays as sub parse' do
225
- expect(value).to eq(expected)
226
- end
227
-
228
- context 'when there are nil values and compact is true' do
229
- before do
230
- json["animals"].last['race'] = nil
231
- end
232
- let(:expected) do
233
- ['European squid', 'Macaque monkey']
234
- end
235
-
236
- it 'eliminate nil values' do
237
- expect(value).to eq(expected)
238
- end
239
- end
240
- end
241
-
242
157
  context 'when passing an after filter' do
243
158
  let(:attribute) { :games_filtered }
244
159
 
@@ -247,71 +162,16 @@ describe JsonParser do
247
162
  end
248
163
  end
249
164
 
250
- context 'when using a snake case' do
251
- class JsonParser::Dummy
252
- json_parse :snake_cased, case: :snake
253
- end
254
-
255
- let(:json) { { snake_cased: 'snake', snakeCased: 'Camel' }.stringify_keys }
256
- let(:attribute) { :snake_cased }
257
-
258
- it 'fetches from snake cased fields' do
259
- expect(value).to eq('snake')
260
- end
261
- end
262
-
263
- context 'when using a upper camel case' do
165
+ context 'when casting the result' do
264
166
  class JsonParser::Dummy
265
- json_parse :upper_case, case: :upper_camel
266
- end
267
-
268
- let(:json) { { UpperCase: 'upper', upperCase: 'lower' }.stringify_keys }
269
- let(:attribute) { :upper_case }
270
-
271
- it 'fetches from upper camel cased fields' do
272
- expect(value).to eq('upper')
273
- end
274
- end
275
-
276
- context 'when using a symbol keys' do
277
- let(:json) { load_json_fixture_file('json_parser.json').symbolize_keys }
278
- let(:attribute) { :id }
279
-
280
- it 'fetches from symbol keys' do
281
- expect(value).to eq(json[:id])
282
- end
283
-
284
- context 'parser finds a nil attribute' do
285
- let(:attribute) { :model }
286
-
287
- it 'returns nil' do
288
- expect(value).to be_nil
289
- end
290
-
291
- it do
292
- expect { value }.not_to raise_error
293
- end
167
+ json_parse :float_value, type: :float
294
168
  end
295
- end
296
169
 
297
- context 'when using key with false value' do
298
- let(:attribute) { :has_money }
299
- before do
300
- json['hasMoney'] = false
301
- end
170
+ let(:json) { { floatValue: '1' } }
171
+ let(:attribute) { :float_value }
302
172
 
303
- context 'with string keys' do
304
- it { expect(value).to be_falsey }
305
- it { expect(value).not_to be_nil }
306
- end
307
-
308
- context 'with symbol keys' do
309
- before do
310
- json.symbolize_keys!
311
- end
312
-
313
- it { expect(value).to be_falsey }
314
- it { expect(value).not_to be_nil }
173
+ it do
174
+ expect(value).to be_a(Float)
315
175
  end
316
176
  end
317
177
  end
@@ -0,0 +1,19 @@
1
+ shared_context 'a result that is type cast' do |types|
2
+ types.each do |type, clazz|
3
+ context "with #{type} type" do
4
+ let(:type) { type }
5
+
6
+ it do
7
+ expect(cast).to be_a(clazz)
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+ shared_context 'casts basic types' do
14
+ it_behaves_like 'a result that is type cast', {
15
+ integer: Integer,
16
+ float: Float,
17
+ string: String
18
+ }
19
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bidu Dev's Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-08 00:00:00.000000000 Z
11
+ date: 2015-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -102,6 +102,7 @@ extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
104
  - .gitignore
105
+ - .rspec
105
106
  - Gemfile
106
107
  - Gemfile.lock
107
108
  - Guardfile
@@ -109,14 +110,23 @@ files:
109
110
  - README.md
110
111
  - Rakefile
111
112
  - json_parser.gemspec
113
+ - lib/concerns/options_parser.rb
114
+ - lib/concerns/type_cast.rb
112
115
  - lib/json_parser.rb
113
116
  - lib/json_parser/class_methods.rb
117
+ - lib/json_parser/class_methods/builder.rb
118
+ - lib/json_parser/crawler.rb
114
119
  - lib/json_parser/fetcher.rb
115
120
  - lib/json_parser/version.rb
121
+ - lib/json_parser/wrapper.rb
116
122
  - spec/fixtures/json_parser.json
123
+ - spec/lib/json_parser/crawler_spec.rb
124
+ - spec/lib/json_parser/fetcher_spec.rb
125
+ - spec/lib/json_parser/wrapper_spec.rb
117
126
  - spec/lib/json_parser_spec.rb
118
127
  - spec/spec_helper.rb
119
128
  - spec/support/fixture_helpers.rb
129
+ - spec/support/shared_examples/wrapper.rb
120
130
  homepage: https://github.com/Bidu/json_parser
121
131
  licenses: []
122
132
  metadata: {}
@@ -136,12 +146,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
136
146
  version: '0'
137
147
  requirements: []
138
148
  rubyforge_project:
139
- rubygems_version: 2.2.2
149
+ rubygems_version: 2.4.6
140
150
  signing_key:
141
151
  specification_version: 4
142
152
  summary: Json Parser
143
153
  test_files:
144
154
  - spec/fixtures/json_parser.json
155
+ - spec/lib/json_parser/crawler_spec.rb
156
+ - spec/lib/json_parser/fetcher_spec.rb
157
+ - spec/lib/json_parser/wrapper_spec.rb
145
158
  - spec/lib/json_parser_spec.rb
146
159
  - spec/spec_helper.rb
147
160
  - spec/support/fixture_helpers.rb
161
+ - spec/support/shared_examples/wrapper.rb