json_resource 1.0.0 → 1.1.1

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
  SHA256:
3
- metadata.gz: dbada0c6c6821280079957d75f002a39fa338c6566a4daf7cda3650b98fb29fd
4
- data.tar.gz: a232cf53b5e86dd6e9df328786c5db0ab150747284e11682d5b51bf426fef46c
3
+ metadata.gz: 9c5d0ad6feca66b6bd7524037d69edf9da40ba45c5f25a6441ef4543d174e5ad
4
+ data.tar.gz: 6ee0efc65381f5243b3da05ef710dc7a8ea6e296708e2a4224c680b728fb9331
5
5
  SHA512:
6
- metadata.gz: 1a8a3aae1d4e7b21df4e09cc5d8da6f807219e6fc3841c02ca200d9bce621aa222f5e4caa1ee61b190c6041d2b1269674dcaf9b3453e4d8ccdebf3bc41e3e518
7
- data.tar.gz: ab5f72f1a266e1ba3e8ae993d951339c9f63c66a5960e241968931343233ce2bafdcf8667eb58378589e698b628573d0f4b2f9b54d427693667095c574348d5b
6
+ metadata.gz: f534f05c6e7748186cfb3373c3b55c5891d0c572be08b917f380d4cf49443a60dbdda258a3dda9778edd9b623eb4f4d45cff2c5223423c8ad450cacfde050030
7
+ data.tar.gz: 0f7703523f9b619ce117fb889fd6f9eba4738a6ceeed9d5e043edc54c1c057f25ba4d788da958b2a7121ddd93a5688787477618f0a247ff294305b804dc89a77
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 1.1.0 – 2023-11-01
2
+
3
+ - Improve BigDecimal conversion
4
+
1
5
  ## 1.0.0
2
6
 
3
7
  - First release
data/README.md CHANGED
@@ -62,3 +62,68 @@ posts.first.body => 'Lorem ipsum'
62
62
  posts.first.status_text => 'published'
63
63
  posts.first.comments.first.author => 'Mr. Spock'
64
64
  ```
65
+
66
+ ## Instantiation
67
+
68
+ To instantiate collections, use `collection_from_json` on a JSON array.
69
+
70
+ To instantiate single objects, use `from_json` on a JSON hash.
71
+
72
+
73
+ ## Field types
74
+
75
+ Attributes can have one of the following types:
76
+
77
+ | Type | Conversion | Options |
78
+ | ----------- | ------------------- | ------------------------- |
79
+ | `:string` | `value` | |
80
+ | `:integer` | `value.to_i` | |
81
+ | `:float` | `value.to_f` | |
82
+ | `:boolean` | any of `[true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON']` | |
83
+ | `:decimal` | direct, or `to_d` | `:precision`, `:scale` |
84
+ | `:date` | `Date.parse` | |
85
+ | `:time` | `Time.parse` | |
86
+
87
+
88
+ ## Extracting data
89
+
90
+ Sometimes, APIs return data wrapped within arrays of hashes of arrays etc:
91
+
92
+ ```json
93
+ {
94
+ "data": [
95
+ {
96
+ "status": "ok"
97
+ },
98
+ {
99
+ "planets": [
100
+ {
101
+ "name": "Earth",
102
+ "mass": 5.9722E+24,
103
+ "orbit": 1.000
104
+ },
105
+ {
106
+ "name": "Jupiter",
107
+ "mass": 1.8990E+27,
108
+ "orbit": 5.205
109
+ }
110
+ ]
111
+ }
112
+ ]
113
+ }
114
+ ```
115
+
116
+ ```ruby
117
+ class Planet
118
+ include JsonResource::Model
119
+
120
+ attribute :name, type: :string
121
+ attribute :mass, type: :decimal, precision: 10, scale: 4
122
+ end
123
+ ```
124
+
125
+ To dig for this data, a call-sequence can be provided as the `root` option.
126
+
127
+ ```ruby
128
+ planets = Planet.collection_from_json(json, root: %w[data [1] planets])
129
+ ```
@@ -3,6 +3,7 @@ module JsonResource
3
3
 
4
4
  module Model
5
5
  TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON'].to_set
6
+ BIGDECIMAL_PRECISION = 18
6
7
 
7
8
  def self.included(base)
8
9
  base.extend ClassMethods
@@ -23,7 +24,7 @@ module JsonResource
23
24
  if path = attribute_path(name)
24
25
  value = json_dig(json, *path)
25
26
  if !value.nil? && type = attribute_type(name)
26
- value = cast_to(type, value)
27
+ value = cast_to(type, value, name)
27
28
  end
28
29
  attrs[name] = value
29
30
  end
@@ -46,7 +47,7 @@ module JsonResource
46
47
 
47
48
  def collection_from_json(obj, defaults: {}, root: nil)
48
49
  json = parse(obj)
49
- json = json_dig(json, root) if root
50
+ json = json_dig(json, *root) if root
50
51
  json.map { |hsh| from_json(hsh, defaults: defaults) }.compact
51
52
  end
52
53
 
@@ -95,16 +96,20 @@ module JsonResource
95
96
  end
96
97
 
97
98
  [:attribute, :object, :collection].each do |method_name|
99
+ define_method "#{method_name}_options" do |name|
100
+ send(method_name.to_s.pluralize).try(:[], name)
101
+ end
102
+
98
103
  define_method "#{method_name}_path" do |name|
99
- options = send(method_name.to_s.pluralize)
100
- Array(options[name].try(:[], :path)).presence || [inflect(name)]
104
+ options = send("#{method_name}_options", name)
105
+ Array(options.try(:[], :path)).presence || [inflect(name)]
101
106
  end
102
107
  end
103
108
 
104
109
  def attribute_type(name)
105
110
  attributes[name] && attributes[name][:type]
106
111
  end
107
-
112
+
108
113
  def object_class(name)
109
114
  if objects[name] && class_name = objects[name][:class_name]
110
115
  class_name.constantize
@@ -121,13 +126,13 @@ module JsonResource
121
126
  end
122
127
  end
123
128
 
124
- def cast_to(type, value) # only called for non-nil values
129
+ def cast_to(type, value, name) # only called for non-nil values
125
130
  case type
126
131
  when :string then value
127
132
  when :integer then value.to_i
128
133
  when :float then value.to_f
129
134
  when :boolean then cast_to_boolean(value)
130
- when :decimal then BigDecimal(value)
135
+ when :decimal then cast_to_big_decimal(value, **attribute_options(name))
131
136
  when :date then value.presence && Date.parse(value)
132
137
  when :time then value.presence && Time.parse(value)
133
138
  else
@@ -142,6 +147,26 @@ module JsonResource
142
147
  TRUE_VALUES.include?(value)
143
148
  end
144
149
  end
150
+
151
+ def cast_to_big_decimal(value, scale: nil, precision: nil, **)
152
+ cast_value = case value
153
+ when ::Float
154
+ precision ||= BIGDECIMAL_PRECISION
155
+ float_precision = precision.to_i > ::Float::DIG + 1 ? ::Float::DIG + 1 : precision.to_i
156
+ BigDecimal(value, float_precision)
157
+ when ::Numeric
158
+ BigDecimal(value, precision || BIGDECIMAL_PRECISION)
159
+ when ::String
160
+ begin
161
+ value.to_d
162
+ rescue ArgumentError
163
+ BigDecimal(0)
164
+ end
165
+ else
166
+ value.respond_to?(:to_d) ? value.to_d : BigDecimal(value.to_s)
167
+ end
168
+ scale ? cast_value.round(scale) : cast_value
169
+ end
145
170
 
146
171
  def parse(obj)
147
172
  case obj
@@ -1,3 +1,3 @@
1
1
  module JsonResource
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_resource
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthias Grosser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-10 00:00:00.000000000 Z
11
+ date: 2023-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -52,7 +52,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - ">="
54
54
  - !ruby/object:Gem::Version
55
- version: 2.6.0
55
+ version: 2.7.0
56
56
  required_rubygems_version: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - ">="