json_parser 0.1.0 → 1.0.0

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