code-ruby 0.11.0 → 0.12.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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +2 -2
  3. data/bin/code +6 -0
  4. data/lib/code/node/base_10.rb +2 -2
  5. data/lib/code/node/base_16.rb +1 -5
  6. data/lib/code/node/base_2.rb +1 -5
  7. data/lib/code/node/base_8.rb +1 -5
  8. data/lib/code/node/call.rb +4 -4
  9. data/lib/code/node/code.rb +2 -1
  10. data/lib/code/node/decimal.rb +1 -4
  11. data/lib/code/node/dictionary.rb +6 -2
  12. data/lib/code/node/function.rb +3 -3
  13. data/lib/code/node/function_parameter.rb +5 -1
  14. data/lib/code/node/if.rb +2 -1
  15. data/lib/code/node/list.rb +2 -1
  16. data/lib/code/node/statement.rb +23 -23
  17. data/lib/code/node/string.rb +2 -1
  18. data/lib/code/object/argument.rb +4 -3
  19. data/lib/code/object/boolean.rb +5 -4
  20. data/lib/code/object/class.rb +4 -3
  21. data/lib/code/object/code.rb +33 -0
  22. data/lib/code/object/context.rb +7 -5
  23. data/lib/code/object/date.rb +31 -6
  24. data/lib/code/object/decimal.rb +36 -31
  25. data/lib/code/object/dictionary.rb +4 -4
  26. data/lib/code/object/duration.rb +8 -5
  27. data/lib/code/object/function.rb +42 -26
  28. data/lib/code/object/global.rb +58 -38
  29. data/lib/code/object/integer.rb +23 -26
  30. data/lib/code/object/list.rb +5 -5
  31. data/lib/code/object/nothing.rb +2 -4
  32. data/lib/code/object/parameter.rb +43 -0
  33. data/lib/code/object/range.rb +13 -11
  34. data/lib/code/object/string.rb +7 -7
  35. data/lib/code/object/time.rb +15 -8
  36. data/lib/code/object.rb +102 -5
  37. data/lib/code/parser.rb +1 -1
  38. data/lib/code/type.rb +10 -2
  39. data/lib/code/version.rb +1 -1
  40. data/lib/code-ruby.rb +6 -0
  41. data/lib/code.rb +8 -5
  42. data/spec/code/object/dictionary_spec.rb +0 -2
  43. data/spec/code_spec.rb +122 -16
  44. metadata +4 -3
  45. data/lib/code/object/number.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97ce31f3a36a57e14f607ded3383aa3c71866824c6e57541c70d48962c77b9ef
4
- data.tar.gz: '0229023c391084763f03d2ffbfd82af81da2d996666719a49ad169d7740c4d6c'
3
+ metadata.gz: b04f0e4774e945bbf969c0159eaf23db99d9208faa98e4ae2ed575c1a363baf9
4
+ data.tar.gz: bf3de392fa1af6540d653d35248089d49b39da4addfd539e7594e0ac66c15def
5
5
  SHA512:
6
- metadata.gz: 996b1594dbc1192dbad2b0c64d605d9eccff6d5622437ef5974464648e5f2cd2ee57aad50fce9279f8027f1378fc7c2652106265a2fc79bbe21b224210228c9d
7
- data.tar.gz: ec405b4bc88648344f4860fb7350695aa447a5905e9a56e7230c771d5ea76e22515fe74ac0fc30771e27a9d67f4eda85b0d2475484d81a5d2c604c5a901913ae
6
+ metadata.gz: 05a921e1f388872311df4f61df4dcf808cc1d4bdaccbf2bdbdd65cc58b5495edac205c003397c83254f257a9ad114b093f2470018dc12fc4d7998ae7e1feaa7d
7
+ data.tar.gz: f856f404a8bebf4d802d2d0ab427e091f5c556da3cd24c3f583a09bf646dedef086e31b933c8933f86868ec9b501d1594f8d7e5272bcdbf1a7dea9571e825cf6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- code-ruby (0.10.4)
4
+ code-ruby (0.11.0)
5
5
  activesupport (~> 7)
6
6
  bigdecimal (~> 3)
7
7
  json (~> 2)
@@ -30,7 +30,7 @@ GEM
30
30
  i18n (1.14.1)
31
31
  concurrent-ruby (~> 1.0)
32
32
  json (2.7.1)
33
- language-ruby (0.7.0)
33
+ language-ruby (0.8.0)
34
34
  zeitwerk (~> 2)
35
35
  minitest (5.22.2)
36
36
  mutex_m (0.2.0)
data/bin/code CHANGED
@@ -42,6 +42,12 @@ argv =
42
42
  "Set timeout in seconds"
43
43
  ) { |timeout| options[:timeout] = timeout.to_f }
44
44
 
45
+ opts.on(
46
+ "-z TIME_ZONE",
47
+ "--time-zone TIME_ZONE",
48
+ "Set time zone"
49
+ ) { |time_zone| Time.zone = time_zone }
50
+
45
51
  opts.on("--profile", "Profile Ruby code") do |_timeout|
46
52
  require "ruby-prof"
47
53
  options[:profile] = true
@@ -16,9 +16,9 @@ class Code
16
16
  if @exponent && @whole
17
17
  exponent = @exponent.evaluate(**args)
18
18
  if exponent.is_a?(Object::Integer)
19
- Object::Integer.new(@whole, exponent:)
19
+ Object::Integer.new(@whole, exponent)
20
20
  else
21
- Object::Decimal.new(@whole, exponent:)
21
+ Object::Decimal.new(@whole, exponent)
22
22
  end
23
23
  elsif @whole
24
24
  Object::Integer.new(@whole.to_i)
@@ -9,11 +9,7 @@ class Code
9
9
  end
10
10
 
11
11
  def evaluate(**_args)
12
- if @base_16
13
- Object::Integer.new(@base_16.to_i(16))
14
- else
15
- Object::Nothing.new
16
- end
12
+ @base_16 ? Object::Integer.new(@base_16.to_i(16)) : Object::Nothing.new
17
13
  end
18
14
  end
19
15
  end
@@ -9,11 +9,7 @@ class Code
9
9
  end
10
10
 
11
11
  def evaluate(**_args)
12
- if @base_2
13
- Object::Integer.new(@base_2.to_i(2))
14
- else
15
- Object::Nothing.new
16
- end
12
+ @base_2 ? Object::Integer.new(@base_2.to_i(2)) : Object::Nothing.new
17
13
  end
18
14
  end
19
15
  end
@@ -9,11 +9,7 @@ class Code
9
9
  end
10
10
 
11
11
  def evaluate(**_args)
12
- if @base_8
13
- Object::Integer.new(@base_8.to_i(8))
14
- else
15
- Object::Nothing.new
16
- end
12
+ @base_8 ? Object::Integer.new(@base_8.to_i(8)) : Object::Nothing.new
17
13
  end
18
14
  end
19
15
  end
@@ -13,9 +13,7 @@ class Code
13
13
  end
14
14
 
15
15
  def evaluate(**_args)
16
- Object::Argument.new(
17
- Object::Function.new(parameters: @parameters, body: @body)
18
- )
16
+ Object::Argument.new(Object::Function.new(@parameters, @body))
19
17
  end
20
18
  end
21
19
 
@@ -25,7 +23,9 @@ class Code
25
23
  @arguments = parsed.delete(:arguments).presence || []
26
24
  @arguments.map! { |argument| CallArgument.new(argument) }
27
25
 
28
- @block = Call::Block.new(parsed.delete(:block).presence) if parsed.key?(:block)
26
+ if parsed.key?(:block)
27
+ @block = Call::Block.new(parsed.delete(:block).presence)
28
+ end
29
29
  end
30
30
 
31
31
  def evaluate(**args)
@@ -5,7 +5,8 @@ class Code
5
5
  class Code < Node
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
- @statements = (parsed.presence || []).map { |statement| Statement.new(statement) }
8
+ @statements =
9
+ (parsed.presence || []).map { |statement| Statement.new(statement) }
9
10
  end
10
11
 
11
12
  def evaluate(**args)
@@ -14,10 +14,7 @@ class Code
14
14
 
15
15
  def evaluate(**args)
16
16
  if @exponent && @decimal
17
- Object::Decimal.new(
18
- @decimal,
19
- exponent: @exponent.evaluate(**args)
20
- )
17
+ Object::Decimal.new(@decimal, @exponent.evaluate(**args))
21
18
  elsif @decimal
22
19
  Object::Decimal.new(@decimal)
23
20
  else
@@ -32,12 +32,16 @@ class Code
32
32
  def initialize(parsed)
33
33
  return if parsed.blank?
34
34
  @key_values = parsed.presence || []
35
- @key_values.map! { |key_value| Node::Dictionary::KeyValue.new(key_value) }
35
+ @key_values.map! do |key_value|
36
+ Node::Dictionary::KeyValue.new(key_value)
37
+ end
36
38
  end
37
39
 
38
40
  def evaluate(**args)
39
41
  ::Code::Object::Dictionary.new(
40
- (@key_values || []).map { |key_value| key_value.evaluate(**args) }.to_h
42
+ (@key_values || [])
43
+ .map { |key_value| key_value.evaluate(**args) }
44
+ .to_h
41
45
  )
42
46
  end
43
47
  end
@@ -6,13 +6,13 @@ class Code
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
8
  @parameters = parsed.delete(:parameters).presence || []
9
- @parameters.map! { |parameter| Node::FunctionParameter.new(parameter) }
9
+ @parameters.map! { |parameter| FunctionParameter.new(parameter) }
10
10
 
11
- @body = Node::Code.new(parsed.delete(:body).presence)
11
+ @body = Code.new(parsed.delete(:body).presence)
12
12
  end
13
13
 
14
14
  def evaluate(**_args)
15
- ::Code::Object::Function.new(parameters: @parameters, body: @body)
15
+ Object::Function.new(@parameters, @body)
16
16
  end
17
17
  end
18
18
  end
@@ -10,7 +10,7 @@ class Code
10
10
  end
11
11
 
12
12
  def name
13
- ::Code::Object::String.new(@name)
13
+ Object::String.new(@name)
14
14
  end
15
15
 
16
16
  def regular?
@@ -28,6 +28,10 @@ class Code
28
28
  def keyword_splat?
29
29
  false
30
30
  end
31
+
32
+ def default
33
+ nil
34
+ end
31
35
  end
32
36
  end
33
37
  end
data/lib/code/node/if.rb CHANGED
@@ -25,7 +25,8 @@ class Code
25
25
  def initialize(parsed)
26
26
  return if parsed.blank?
27
27
  @first_operator = parsed.delete(:first_operator).presence
28
- @first_statement = Node::Statement.new(parsed.delete(:first_statement).presence)
28
+ @first_statement =
29
+ Node::Statement.new(parsed.delete(:first_statement).presence)
29
30
  @first_body = Node::Code.new(parsed.delete(:first_body).presence)
30
31
  @elses = (parsed.delete(:elses).presence || [])
31
32
  @elses.map! { |elses| Node::If::Else.new(elses) }
@@ -5,7 +5,8 @@ class Code
5
5
  class List < Node
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
- @elements = (parsed.presence || []).map { |element| Node::Code.new(element) }
8
+ @elements =
9
+ (parsed.presence || []).map { |element| Node::Code.new(element) }
9
10
  end
10
11
 
11
12
  def evaluate(**args)
@@ -7,51 +7,51 @@ class Code
7
7
  return if parsed.blank?
8
8
 
9
9
  if parsed.key?(:nothing)
10
- @statement = Node::Nothing.new(parsed.delete(:nothing))
10
+ @statement = Nothing.new(parsed.delete(:nothing))
11
11
  elsif parsed.key?(:boolean)
12
- @statement = Node::Boolean.new(parsed.delete(:boolean))
12
+ @statement = Boolean.new(parsed.delete(:boolean))
13
13
  elsif parsed.key?(:group)
14
- @statement = Node::Code.new(parsed.delete(:group))
14
+ @statement = Code.new(parsed.delete(:group))
15
15
  elsif parsed.key?(:call)
16
- @statement = Node::Call.new(parsed.delete(:call))
16
+ @statement = Call.new(parsed.delete(:call))
17
17
  elsif parsed.key?(:number)
18
- @statement = Node::Number.new(parsed.delete(:number))
18
+ @statement = Number.new(parsed.delete(:number))
19
19
  elsif parsed.key?(:string)
20
- @statement = Node::String.new(parsed.delete(:string))
20
+ @statement = String.new(parsed.delete(:string))
21
21
  elsif parsed.key?(:list)
22
- @statement = Node::List.new(parsed.delete(:list))
22
+ @statement = List.new(parsed.delete(:list))
23
23
  elsif parsed.key?(:dictionnary)
24
- @statement = Node::Dictionary.new(parsed.delete(:dictionnary))
24
+ @statement = Dictionary.new(parsed.delete(:dictionnary))
25
25
  elsif parsed.key?(:chained_call)
26
- @statement = Node::ChainedCall.new(parsed.delete(:chained_call))
26
+ @statement = ChainedCall.new(parsed.delete(:chained_call))
27
27
  elsif parsed.key?(:left_operation)
28
- @statement = Node::LeftOperation.new(parsed.delete(:left_operation))
28
+ @statement = LeftOperation.new(parsed.delete(:left_operation))
29
29
  elsif parsed.key?(:right_operation)
30
- @statement = Node::RightOperation.new(parsed.delete(:right_operation))
30
+ @statement = RightOperation.new(parsed.delete(:right_operation))
31
31
  elsif parsed.key?(:function)
32
- @statement = Node::Function.new(parsed.delete(:function))
32
+ @statement = Function.new(parsed.delete(:function))
33
33
  elsif parsed.key?(:negation)
34
- @statement = Node::Negation.new(parsed.delete(:negation))
34
+ @statement = Negation.new(parsed.delete(:negation))
35
35
  elsif parsed.key?(:power)
36
- @statement = Node::Power.new(parsed.delete(:power))
36
+ @statement = Power.new(parsed.delete(:power))
37
37
  elsif parsed.key?(:unary_minus)
38
- @statement = Node::UnaryMinus.new(parsed.delete(:unary_minus))
38
+ @statement = UnaryMinus.new(parsed.delete(:unary_minus))
39
39
  elsif parsed.key?(:ternary)
40
- @statement = Node::Ternary.new(parsed.delete(:ternary))
40
+ @statement = Ternary.new(parsed.delete(:ternary))
41
41
  elsif parsed.key?(:rescue)
42
- @statement = Node::Rescue.new(parsed.delete(:rescue))
42
+ @statement = Rescue.new(parsed.delete(:rescue))
43
43
  elsif parsed.key?(:not)
44
- @statement = Node::Not.new(parsed.delete(:not))
44
+ @statement = Not.new(parsed.delete(:not))
45
45
  elsif parsed.key?(:if_modifier)
46
- @statement = Node::IfModifier.new(parsed.delete(:if_modifier))
46
+ @statement = IfModifier.new(parsed.delete(:if_modifier))
47
47
  elsif parsed.key?(:if)
48
- @statement = Node::If.new(parsed.delete(:if))
48
+ @statement = If.new(parsed.delete(:if))
49
49
  elsif parsed.key?(:while)
50
- @statement = Node::While.new(parsed.delete(:while))
50
+ @statement = While.new(parsed.delete(:while))
51
51
  elsif parsed.key?(:splat)
52
- @statement = Node::Splat.new(parsed.delete(:splat))
52
+ @statement = Splat.new(parsed.delete(:splat))
53
53
  elsif parsed.key?(:square_bracket)
54
- @statement = Node::SquareBracket.new(parsed.delete(:square_bracket))
54
+ @statement = SquareBracket.new(parsed.delete(:square_bracket))
55
55
  end
56
56
  end
57
57
 
@@ -53,7 +53,8 @@ class Code
53
53
 
54
54
  def initialize(parsed)
55
55
  return if parsed.blank?
56
- @parts = (parsed.presence || []).map { |part| Node::String::Part.new(part) }
56
+ @parts =
57
+ (parsed.presence || []).map { |part| Node::String::Part.new(part) }
57
58
  end
58
59
 
59
60
  def evaluate(**args)
@@ -5,9 +5,10 @@ class Code
5
5
  class Argument < Object
6
6
  attr_reader :value, :name
7
7
 
8
- def initialize(value, name: nil)
9
- @value = value
10
- @name = name
8
+ def initialize(*args, **_kargs, &_block)
9
+ @value = args.first.presence || Nothing.new
10
+ @name = args.second.present? ? String.new(args.second) : nil
11
+ super
11
12
  end
12
13
 
13
14
  def keyword?
@@ -3,10 +3,11 @@
3
3
  class Code
4
4
  class Object
5
5
  class Boolean < ::Code::Object
6
- attr_reader :raw
7
-
8
- def initialize(raw)
9
- @raw = (raw.is_a?(Object) ? raw.truthy? : !!raw)
6
+ def initialize(*args, **_kargs, &_block)
7
+ raw = args.first || Nothing.new
8
+ raw = raw.raw if raw.is_a?(Object)
9
+ @raw = !!raw
10
+ super
10
11
  end
11
12
 
12
13
  def self.name
@@ -3,11 +3,12 @@
3
3
  class Code
4
4
  class Object
5
5
  class Class < Object
6
- attr_reader :raw
7
-
8
- def initialize(raw)
6
+ def initialize(*args, **_kargs, &_block)
7
+ raw = args.first || Nothing.new
9
8
  raw = raw.raw if raw.is_a?(Class)
9
+ raw = raw.class if raw.is_an?(Object)
10
10
  @raw = raw
11
+ super
11
12
  end
12
13
 
13
14
  def call(...)
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Code
4
+ class Object
5
+ class Code < Object
6
+ def initialize(*args, **_kargs, &_block)
7
+ raw = args.first.presence || Nothing.new
8
+ @raw = raw.is_a?(Node) ? raw : Node::Code.new(::Code.parse(raw.to_s))
9
+ super
10
+ end
11
+
12
+ def self.name
13
+ "Code"
14
+ end
15
+
16
+ def evaluate(...)
17
+ raw.evaluate(...)
18
+ end
19
+
20
+ def inspect
21
+ "code"
22
+ end
23
+
24
+ def to_s
25
+ "code"
26
+ end
27
+
28
+ def as_json(...)
29
+ "code".as_json(...)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -5,10 +5,12 @@ class Code
5
5
  class Context < Dictionary
6
6
  attr_reader :parent
7
7
 
8
- def initialize(raw = {}, parent: nil)
9
- raw = raw.raw if raw.is_a?(Dictionary)
8
+ def initialize(*args, **_kargs, &_block)
9
+ raw = args.first || Dictionary.new
10
+ raw = raw.raw if raw.is_a?(Object)
10
11
  @raw = raw.to_h
11
- @parent = parent
12
+ @parent = Context.new(args.second) if args.second
13
+ super
12
14
  end
13
15
 
14
16
  def self.name
@@ -21,12 +23,12 @@ class Code
21
23
  elsif parent?
22
24
  parent.lookup!(identifier)
23
25
  else
24
- raise Code::Error::Undefined, "#{identifier} is not defined"
26
+ raise Error::Undefined, "#{identifier} is not defined"
25
27
  end
26
28
  end
27
29
 
28
30
  def merge(other)
29
- Context.new(raw.merge(other.raw), parent: parent || other.parent)
31
+ Context.new(raw.merge(other.raw), parent || other.parent)
30
32
  end
31
33
 
32
34
  def parent?
@@ -3,11 +3,12 @@
3
3
  class Code
4
4
  class Object
5
5
  class Date < Object
6
- attr_reader :raw
7
-
8
- def initialize(date)
9
- date = date.raw if date.is_a?(Date)
10
- @raw = date.to_date
6
+ def initialize(*args, **_kargs, &_block)
7
+ raw = args.map(&:to_s).join("-").presence || ::Date.current.to_s
8
+ @raw = ::Date.parse(raw)
9
+ super
10
+ rescue ::Date::Error
11
+ raise Error, "#{raw.inspect} is an invalid date"
11
12
  end
12
13
 
13
14
  def self.name
@@ -21,14 +22,38 @@ class Code
21
22
  when "tomorrow"
22
23
  sig(args)
23
24
  code_tomorrow
25
+ when "yesterday"
26
+ sig(args)
27
+ code_yesterday
28
+ when "today"
29
+ sig(args)
30
+ code_today
31
+ when "now"
32
+ sig(args)
33
+ code_now
24
34
  else
25
35
  super
26
36
  end
27
37
  end
28
38
 
39
+ def self.code_now
40
+ ::Time.zone ||= Time::DEFAULT_ZONE
41
+ new(::Time.zone.now.beginning_of_day)
42
+ end
43
+
44
+ def self.code_today
45
+ ::Time.zone ||= Time::DEFAULT_ZONE
46
+ new(::Time.zone.now.beginning_of_day)
47
+ end
48
+
29
49
  def self.code_tomorrow
30
50
  ::Time.zone ||= Time::DEFAULT_ZONE
31
- new(::Time.zone.tomorrow)
51
+ new(::Time.zone.tomorrow.beginning_of_day)
52
+ end
53
+
54
+ def self.code_yesterday
55
+ ::Time.zone ||= Time::DEFAULT_ZONE
56
+ new(::Time.zone.yesterday.beginning_of_day)
32
57
  end
33
58
 
34
59
  def inspect
@@ -2,19 +2,16 @@
2
2
 
3
3
  class Code
4
4
  class Object
5
- class Decimal < ::Code::Object::Number
6
- attr_reader :raw
7
-
8
- def initialize(decimal, exponent: nil)
9
- decimal = decimal.raw if decimal.is_a?(Decimal)
10
- @raw = BigDecimal(decimal)
11
-
12
- return unless exponent
13
- unless exponent.is_a?(Number)
14
- raise ::Code::Error::TypeError, "exponent is not a number"
15
- end
16
-
17
- @raw *= 10**exponent.raw
5
+ class Decimal < Object
6
+ def initialize(*args, **_kargs, &_block)
7
+ decimal = args.first || "0"
8
+ exponent = args.second || "0"
9
+ decimal = decimal.raw if decimal.is_an?(Object)
10
+ exponent = exponent.raw if exponent.is_an?(Object)
11
+ @raw = decimal.to_d * 10**exponent.to_d
12
+ super
13
+ rescue FloatDomainError => e
14
+ raise Error, "#{decimal.inspect} * 10**#{exponent.inspect} is invalid"
18
15
  end
19
16
 
20
17
  def self.name
@@ -28,49 +25,49 @@ class Code
28
25
 
29
26
  case operator.to_s
30
27
  when "%", "modulo"
31
- sig(args) { Number }
28
+ sig(args) { Integer | Decimal }
32
29
  code_modulo(value)
33
30
  when "&", "bitwise_and"
34
- sig(args) { Number }
31
+ sig(args) { Integer | Decimal }
35
32
  code_bitwise_and(value)
36
33
  when "*", "multiplication"
37
- sig(args) { Number }
34
+ sig(args) { Integer | Decimal }
38
35
  code_multiplication(value)
39
36
  when "**", "power"
40
- sig(args) { Number }
37
+ sig(args) { Integer | Decimal }
41
38
  code_power(value)
42
39
  when "+", "plus"
43
40
  sig(args) { Object.maybe }
44
41
  value ? code_plus(value) : self
45
42
  when "-", "minus"
46
- sig(args) { Number.maybe }
43
+ sig(args) { (Integer | Decimal).maybe }
47
44
  value ? code_minus(value) : code_unary_minus
48
45
  when "/", "division"
49
- sig(args) { Number }
46
+ sig(args) { Integer | Decimal }
50
47
  code_division(value)
51
48
  when "<", "inferior"
52
- sig(args) { Number }
49
+ sig(args) { Integer | Decimal }
53
50
  code_inferior(value)
54
51
  when "<<", "left_shift"
55
- sig(args) { Number }
52
+ sig(args) { Integer | Decimal }
56
53
  code_left_shift(value)
57
54
  when "<=", "inferior_or_equal"
58
- sig(args) { Number }
55
+ sig(args) { Integer | Decimal }
59
56
  code_inferior_or_equal(value)
60
57
  when "<=>", "compare"
61
- sig(args) { Number }
58
+ sig(args) { Integer | Decimal }
62
59
  code_compare(value)
63
60
  when ">", "superior"
64
- sig(args) { Number }
61
+ sig(args) { Integer | Decimal }
65
62
  code_superior(value)
66
63
  when ">=", "superior_or_equal"
67
- sig(args) { Number }
64
+ sig(args) { Integer | Decimal }
68
65
  code_superior_or_equal(value)
69
66
  when ">>", "right_shift"
70
- sig(args) { Number }
67
+ sig(args) { Integer | Decimal }
71
68
  code_right_shift(value)
72
69
  when "^", "bitwise_xor"
73
- sig(args) { Number }
70
+ sig(args) { Integer | Decimal }
74
71
  code_bitwise_xor(value)
75
72
  when "abs"
76
73
  sig(args)
@@ -136,7 +133,7 @@ class Code
136
133
  sig(args)
137
134
  code_zero?
138
135
  when "|", "bitwise_or"
139
- sig(args) { Number }
136
+ sig(args) { Integer | Decimal }
140
137
  code_bitwise_or(value)
141
138
  else
142
139
  super
@@ -226,7 +223,7 @@ class Code
226
223
  end
227
224
 
228
225
  def code_plus(other)
229
- if other.is_a?(Number)
226
+ if other.is_an?(Integer) || other.is_a?(Decimal)
230
227
  Decimal.new(raw + other.raw)
231
228
  else
232
229
  String.new(to_s + other.to_s)
@@ -307,12 +304,20 @@ class Code
307
304
  to_s
308
305
  end
309
306
 
307
+ def whole?
308
+ whole == raw
309
+ end
310
+
311
+ def whole
312
+ raw.round
313
+ end
314
+
310
315
  def to_s
311
- raw.to_s("F")
316
+ whole? ? raw.to_i.to_s : raw.to_s("F")
312
317
  end
313
318
 
314
319
  def as_json(...)
315
- raw.as_json(...)
320
+ whole? ? whole.as_json(...) : raw.as_json(...)
316
321
  end
317
322
  end
318
323
  end
@@ -3,11 +3,11 @@
3
3
  class Code
4
4
  class Object
5
5
  class Dictionary < ::Code::Object
6
- attr_reader :raw
7
-
8
- def initialize(raw = {})
9
- raw = raw.raw if raw.is_a?(Dictionary)
6
+ def initialize(*args, **_kargs, &_block)
7
+ raw = args.first || {}
8
+ raw = raw.raw if raw.is_a?(Object)
10
9
  @raw = raw.to_h
10
+ super
11
11
  end
12
12
 
13
13
  def self.name
@@ -3,11 +3,14 @@
3
3
  class Code
4
4
  class Object
5
5
  class Duration < Object
6
- attr_reader :raw
7
-
8
- def initialize(duration)
9
- duration = duration.raw if duration.is_a?(Duration)
10
- @raw = duration
6
+ def initialize(*args, **_kargs, &_block)
7
+ raw = args.first || 0.seconds
8
+ raw = raw.raw if raw.is_an?(Object)
9
+ raw = raw.iso8601 if raw.is_an?(::ActiveSupport::Duration)
10
+ @raw = ::ActiveSupport::Duration.parse(raw.to_s)
11
+ super
12
+ rescue ::ActiveSupport::Duration::ISO8601Parser::ParsingError
13
+ raise Error, "#{raw.inspect} is not a valid duration"
11
14
  end
12
15
 
13
16
  def self.name