Class: Odin::Types::DynValue

Inherits:
Object
  • Object
show all
Defined in:
lib/odin/types/dyn_value.rb

Constant Summary collapse

TYPES =
%i[
  null bool integer float float_raw
  currency currency_raw percent reference binary
  date timestamp time duration
  string array object
].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(type:, value: nil, decimal_places: 0, currency_code: nil) ⇒ DynValue

Returns a new instance of DynValue.



18
19
20
21
22
23
24
# File 'lib/odin/types/dyn_value.rb', line 18

def initialize(type:, value: nil, decimal_places: 0, currency_code: nil)
  @type = type
  @value = value
  @decimal_places = decimal_places
  @currency_code = currency_code&.freeze
  freeze
end

Instance Attribute Details

#currency_codeObject (readonly)

Returns the value of attribute currency_code.



16
17
18
# File 'lib/odin/types/dyn_value.rb', line 16

def currency_code
  @currency_code
end

#decimal_placesObject (readonly)

Returns the value of attribute decimal_places.



16
17
18
# File 'lib/odin/types/dyn_value.rb', line 16

def decimal_places
  @decimal_places
end

#typeObject (readonly)

Returns the value of attribute type.



16
17
18
# File 'lib/odin/types/dyn_value.rb', line 16

def type
  @type
end

#valueObject (readonly)

Returns the value of attribute value.



16
17
18
# File 'lib/odin/types/dyn_value.rb', line 16

def value
  @value
end

Class Method Details

.extract_array(json_string) ⇒ Object

Helpers: parse JSON strings into DynValue arrays/objects

Raises:

  • (ArgumentError)


96
97
98
99
100
101
# File 'lib/odin/types/dyn_value.rb', line 96

def self.extract_array(json_string)
  parsed = JSON.parse(json_string)
  raise ArgumentError, "Not a JSON array" unless parsed.is_a?(::Array)

  of_array(parsed.map { |item| from_json_value(item) })
end

.extract_object(json_string) ⇒ Object

Raises:

  • (ArgumentError)


103
104
105
106
107
108
# File 'lib/odin/types/dyn_value.rb', line 103

def self.extract_object(json_string)
  parsed = JSON.parse(json_string)
  raise ArgumentError, "Not a JSON object" unless parsed.is_a?(::Hash)

  of_object(parsed.transform_values { |v| from_json_value(v) })
end

.from_json_value(val) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/odin/types/dyn_value.rb', line 110

def self.from_json_value(val)
  case val
  when nil         then of_null
  when true, false then of_bool(val)
  when Integer     then of_integer(val)
  when Float       then of_float(val)
  when String      then of_string(val)
  when Array       then of_array(val.map { |v| from_json_value(v) })
  when Hash        then of_object(val.transform_values { |v| from_json_value(v) })
  else of_string(val.to_s)
  end
end

.from_ruby(obj) ⇒ Object

Convert Ruby native object to DynValue



225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/odin/types/dyn_value.rb', line 225

def self.from_ruby(obj)
  case obj
  when DynValue    then obj
  when nil         then of_null
  when true, false then of_bool(obj)
  when Integer     then of_integer(obj)
  when Float       then of_float(obj)
  when BigDecimal  then of_float(obj.to_f)
  when String      then of_string(obj)
  when Array       then of_array(obj.map { |v| from_ruby(v) })
  when Hash        then of_object(obj.transform_keys(&:to_s).transform_values { |v| from_ruby(v) })
  else of_string(obj.to_s)
  end
end

.of_array(items) ⇒ Object



51
52
53
# File 'lib/odin/types/dyn_value.rb', line 51

def self.of_array(items)
  new(type: :array, value: items)
end

.of_binary(data) ⇒ Object



75
76
77
# File 'lib/odin/types/dyn_value.rb', line 75

def self.of_binary(data)
  new(type: :binary, value: data)
end

.of_bool(v) ⇒ Object



31
32
33
# File 'lib/odin/types/dyn_value.rb', line 31

def self.of_bool(v)
  new(type: :bool, value: v)
end

.of_currency(v, dp = 2, code = nil) ⇒ Object



59
60
61
# File 'lib/odin/types/dyn_value.rb', line 59

def self.of_currency(v, dp = 2, code = nil)
  new(type: :currency, value: v.to_f, decimal_places: dp, currency_code: code)
end

.of_currency_raw(raw, dp = 2, code = nil) ⇒ Object



63
64
65
# File 'lib/odin/types/dyn_value.rb', line 63

def self.of_currency_raw(raw, dp = 2, code = nil)
  new(type: :currency_raw, value: raw.to_s, decimal_places: dp, currency_code: code)
end

.of_date(v) ⇒ Object



79
80
81
# File 'lib/odin/types/dyn_value.rb', line 79

def self.of_date(v)
  new(type: :date, value: v)
end

.of_duration(v) ⇒ Object



91
92
93
# File 'lib/odin/types/dyn_value.rb', line 91

def self.of_duration(v)
  new(type: :duration, value: v.to_s)
end

.of_float(v) ⇒ Object



39
40
41
# File 'lib/odin/types/dyn_value.rb', line 39

def self.of_float(v)
  new(type: :float, value: v.to_f)
end

.of_float_raw(raw) ⇒ Object



43
44
45
# File 'lib/odin/types/dyn_value.rb', line 43

def self.of_float_raw(raw)
  new(type: :float_raw, value: raw.to_s)
end

.of_integer(v) ⇒ Object



35
36
37
# File 'lib/odin/types/dyn_value.rb', line 35

def self.of_integer(v)
  new(type: :integer, value: v.to_i)
end

.of_nullObject

Factory methods



27
28
29
# File 'lib/odin/types/dyn_value.rb', line 27

def self.of_null
  new(type: :null)
end

.of_object(entries) ⇒ Object



55
56
57
# File 'lib/odin/types/dyn_value.rb', line 55

def self.of_object(entries)
  new(type: :object, value: entries)
end

.of_percent(v) ⇒ Object



67
68
69
# File 'lib/odin/types/dyn_value.rb', line 67

def self.of_percent(v)
  new(type: :percent, value: v.to_f)
end

.of_reference(p) ⇒ Object



71
72
73
# File 'lib/odin/types/dyn_value.rb', line 71

def self.of_reference(p)
  new(type: :reference, value: p.to_s)
end

.of_string(v) ⇒ Object



47
48
49
# File 'lib/odin/types/dyn_value.rb', line 47

def self.of_string(v)
  new(type: :string, value: v.to_s)
end

.of_time(v) ⇒ Object



87
88
89
# File 'lib/odin/types/dyn_value.rb', line 87

def self.of_time(v)
  new(type: :time, value: v.to_s)
end

.of_timestamp(v) ⇒ Object



83
84
85
# File 'lib/odin/types/dyn_value.rb', line 83

def self.of_timestamp(v)
  new(type: :timestamp, value: v)
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



214
215
216
217
# File 'lib/odin/types/dyn_value.rb', line 214

def ==(other)
  other.is_a?(DynValue) && type == other.type && value == other.value &&
    decimal_places == other.decimal_places && currency_code == other.currency_code
end

#array?Boolean

Returns:

  • (Boolean)


131
# File 'lib/odin/types/dyn_value.rb', line 131

def array?;     type == :array; end

#as_arrayObject



148
# File 'lib/odin/types/dyn_value.rb', line 148

def as_array;   value; end

#as_boolObject

Coercion accessors



144
# File 'lib/odin/types/dyn_value.rb', line 144

def as_bool;    value; end

#as_floatObject



146
# File 'lib/odin/types/dyn_value.rb', line 146

def as_float;   value.to_f; end

#as_intObject



145
# File 'lib/odin/types/dyn_value.rb', line 145

def as_int;     value.to_i; end

#as_objectObject



149
# File 'lib/odin/types/dyn_value.rb', line 149

def as_object;  value; end

#as_stringObject



147
# File 'lib/odin/types/dyn_value.rb', line 147

def as_string;  value.to_s; end

#binary?Boolean

Returns:

  • (Boolean)


134
# File 'lib/odin/types/dyn_value.rb', line 134

def binary?;    type == :binary; end

#bool?Boolean

Returns:

  • (Boolean)


125
# File 'lib/odin/types/dyn_value.rb', line 125

def bool?;      type == :bool; end

#currency?Boolean

Returns:

  • (Boolean)


128
# File 'lib/odin/types/dyn_value.rb', line 128

def currency?;  type == :currency || type == :currency_raw; end

#date?Boolean

Returns:

  • (Boolean)


135
# File 'lib/odin/types/dyn_value.rb', line 135

def date?;      type == :date; end

#duration?Boolean

Returns:

  • (Boolean)


138
# File 'lib/odin/types/dyn_value.rb', line 138

def duration?;  type == :duration; end

#float?Boolean

Returns:

  • (Boolean)


127
# File 'lib/odin/types/dyn_value.rb', line 127

def float?;     type == :float || type == :float_raw; end

#get(key) ⇒ Object

Object/array access helpers



202
203
204
205
206
# File 'lib/odin/types/dyn_value.rb', line 202

def get(key)
  return nil unless object?

  value[key]
end

#get_index(index) ⇒ Object



208
209
210
211
212
# File 'lib/odin/types/dyn_value.rb', line 208

def get_index(index)
  return nil unless array?

  value[index]
end

#hashObject



220
221
222
# File 'lib/odin/types/dyn_value.rb', line 220

def hash
  [type, value, decimal_places, currency_code].hash
end

#integer?Boolean

Returns:

  • (Boolean)


126
# File 'lib/odin/types/dyn_value.rb', line 126

def integer?;   type == :integer; end

#null?Boolean

Type predicates

Returns:

  • (Boolean)


124
# File 'lib/odin/types/dyn_value.rb', line 124

def null?;      type == :null; end

#numeric?Boolean

Returns:

  • (Boolean)


139
# File 'lib/odin/types/dyn_value.rb', line 139

def numeric?;   integer? || float? || currency? || percent?; end

#object?Boolean

Returns:

  • (Boolean)


132
# File 'lib/odin/types/dyn_value.rb', line 132

def object?;    type == :object; end

#percent?Boolean

Returns:

  • (Boolean)


129
# File 'lib/odin/types/dyn_value.rb', line 129

def percent?;   type == :percent; end

#reference?Boolean

Returns:

  • (Boolean)


133
# File 'lib/odin/types/dyn_value.rb', line 133

def reference?; type == :reference; end

#string?Boolean

Returns:

  • (Boolean)


130
# File 'lib/odin/types/dyn_value.rb', line 130

def string?;    type == :string; end

#temporal?Boolean

Returns:

  • (Boolean)


141
# File 'lib/odin/types/dyn_value.rb', line 141

def temporal?; date? || timestamp? || time? || duration?; end

#time?Boolean

Returns:

  • (Boolean)


137
# File 'lib/odin/types/dyn_value.rb', line 137

def time?;      type == :time; end

#timestamp?Boolean

Returns:

  • (Boolean)


136
# File 'lib/odin/types/dyn_value.rb', line 136

def timestamp?; type == :timestamp; end

#to_numberObject

Coerce to numeric value



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/odin/types/dyn_value.rb', line 152

def to_number
  case type
  when :integer then value
  when :float then value
  when :float_raw then value.to_f
  when :currency then value.to_f
  when :currency_raw then value.to_f
  when :percent then value
  when :string
    return value.to_i if value.match?(/\A-?\d+\z/)
    return value.to_f if value.match?(/\A-?\d+(\.\d+)?([eE][+-]?\d+)?\z/)

    0
  when :bool then value ? 1 : 0
  else 0
  end
end

#to_rubyObject

Convert DynValue to Ruby native object



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/odin/types/dyn_value.rb', line 241

def to_ruby
  case type
  when :null then nil
  when :bool then value
  when :integer then value
  when :float then value
  when :float_raw then value.to_f
  when :string then value
  when :currency then value.is_a?(BigDecimal) ? value.to_f : value.to_f
  when :currency_raw then value.to_f
  when :percent then value
  when :date, :timestamp, :time, :duration then value.to_s
  when :reference then value
  when :binary then value
  when :array then value.map(&:to_ruby)
  when :object then value.transform_values(&:to_ruby)
  else value
  end
end

#to_sObject



261
262
263
264
265
266
267
# File 'lib/odin/types/dyn_value.rb', line 261

def to_s
  case type
  when :null then "null"
  when :bool then value.to_s
  else value.to_s
  end
end

#to_stringObject

Coerce to string representation



171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/odin/types/dyn_value.rb', line 171

def to_string
  case type
  when :null then ""
  when :bool then value.to_s
  when :integer, :float, :percent then value.to_s
  when :float_raw, :currency_raw then value.to_s
  when :currency then value.is_a?(BigDecimal) ? value.to_s("F") : value.to_s
  when :string then value
  when :array then JSON.generate(to_ruby)
  when :object then JSON.generate(to_ruby)
  else value.to_s
  end
end

#truthy?Boolean

Truthiness: null/false/0/“” are falsy

Returns:

  • (Boolean)


186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/odin/types/dyn_value.rb', line 186

def truthy?
  case type
  when :null then false
  when :bool then value
  when :integer then value != 0
  when :float, :float_raw then to_number != 0.0
  when :string then !value.empty?
  when :currency, :currency_raw then to_number != 0.0
  when :percent then value != 0.0
  when :array then true
  when :object then true
  else true
  end
end