dentaku 3.3.0 → 3.3.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: d7a7a3fa41f933a1f88a76e736c32e71dcf87f391a7a4ba09d37b2abad8269b2
4
- data.tar.gz: 3045bd6715d486669c2fe015165a2bef31928fccdf4e6a07f59a67257b9f4867
3
+ metadata.gz: b760fc43a6d5745ea9c95827fb0ce03e8fef8453c2264ee1073e5754c2b8d402
4
+ data.tar.gz: 04e03adf0729e170babe62c8f91cc88ca8aa46932dacb694ccfc564696eed765
5
5
  SHA512:
6
- metadata.gz: 2f8b4a5d727ec64a0308a57570fc51ff09864174fd0669956acb6b26b0d6b5694d6a0ec563eb107b577db79dd37ddd383fc36ec47bd17ebb11008981e2d5c729
7
- data.tar.gz: 1cb16ed5d1bbad1c896d3907761206178093531ef02fe27eabaa19e1b5187f66f1d9d6586d410107133c08c520596dd7b9a6d5b47f23decb47e80ed2cbdd0e28
6
+ metadata.gz: 006ec24c2c61758a1b7f5921e181ed49e2d54bf479091f9600ed31019fedd0a9411d744932e7dbf973b2e8fea098ff7299e58fd97851e5b2382a81e05043f8e4
7
+ data.tar.gz: 7f9d3735fc20e918d808158e8c618e11a0021762f102d9d5b32eec7d24f6a28845c01912fbc63c4cb835438f7f8d6d494fe811a5b01e373a5a6296a087c4edda
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.4
2
+ TargetRubyVersion: 2.6
3
3
  # RuboCop has a bunch of cops enabled by default. This setting tells RuboCop
4
4
  # to ignore them, so only the ones explicitly set in this file are enabled.
5
5
  DisabledByDefault: true
@@ -110,7 +110,7 @@ Style/UnneededPercentQ:
110
110
 
111
111
  # Align `end` with the matching keyword or starting expression except for
112
112
  # assignments, where it should be aligned with the LHS.
113
- Lint/EndAlignment:
113
+ Layout/EndAlignment:
114
114
  Enabled: true
115
115
  EnforcedStyleAlignWith: variable
116
116
 
@@ -1,12 +1,10 @@
1
1
  language: ruby
2
2
  sudo: false
3
3
  rvm:
4
- - 2.0.0-p648
5
- - 2.1.10
6
- - 2.2.9
7
- - 2.3.6
8
- - 2.4.3
9
- - 2.5.0
4
+ - 2.3.8
5
+ - 2.4.4
6
+ - 2.5.3
7
+ - 2.6.0
10
8
  before_install:
11
9
  - gem update bundler
12
10
  - gem update --system
@@ -1,5 +1,10 @@
1
1
  # Change Log
2
2
 
3
+ ## [v3.3.1] 2019-03-26
4
+ - better errors for parse failures and exceptions in internal functions
5
+ - fix Ruby 2.6.0 deprecation warnings
6
+ - fix issue with functions in nested case statements
7
+
3
8
  ## [v3.3.0] 2018-12-04
4
9
  - add array literal syntax
5
10
  - return correct type from string function AST nodes
@@ -166,7 +171,8 @@
166
171
  ## [v0.1.0] 2012-01-20
167
172
  - initial release
168
173
 
169
- [HEAD]: https://github.com/rubysolo/dentaku/compare/v3.3.0...HEAD
174
+ [HEAD]: https://github.com/rubysolo/dentaku/compare/v3.3.1...HEAD
175
+ [v3.3.1]: https://github.com/rubysolo/dentaku/compare/v3.3.0...v3.3.1
170
176
  [v3.3.0]: https://github.com/rubysolo/dentaku/compare/v3.2.1...v3.3.0
171
177
  [v3.2.1]: https://github.com/rubysolo/dentaku/compare/v3.2.0...v3.2.1
172
178
  [v3.2.0]: https://github.com/rubysolo/dentaku/compare/v3.1.0...v3.2.0
@@ -40,7 +40,7 @@ module Dentaku
40
40
  end
41
41
 
42
42
  def numeric(val, prefer_integer)
43
- v = BigDecimal.new(val, Float::DIG + 1)
43
+ v = BigDecimal(val, Float::DIG + 1)
44
44
  v = v.to_i if prefer_integer && v.frac.zero?
45
45
  v
46
46
  rescue ::TypeError
@@ -3,6 +3,7 @@ require_relative './case/case_when'
3
3
  require_relative './case/case_then'
4
4
  require_relative './case/case_switch_variable'
5
5
  require_relative './case/case_else'
6
+ require 'dentaku/exceptions'
6
7
 
7
8
  module Dentaku
8
9
  module AST
@@ -11,16 +12,17 @@ module Dentaku
11
12
  @switch = nodes.shift
12
13
 
13
14
  unless @switch.is_a?(AST::CaseSwitchVariable)
14
- raise 'Case missing switch variable'
15
+ raise ParseError.for(:node_invalid), 'Case missing switch variable'
15
16
  end
16
17
 
17
18
  @conditions = nodes
18
19
 
20
+ @else = nil
19
21
  @else = @conditions.pop if @conditions.last.is_a?(AST::CaseElse)
20
22
 
21
23
  @conditions.each do |condition|
22
24
  unless condition.is_a?(AST::CaseConditional)
23
- raise "#{condition} is not a CaseConditional"
25
+ raise ParseError.for(:node_invalid), "#{condition} is not a CaseConditional"
24
26
  end
25
27
  end
26
28
  end
@@ -36,7 +38,7 @@ module Dentaku
36
38
  if @else
37
39
  return @else.value(context)
38
40
  else
39
- raise "No block matched the switch value '#{switch_value}'"
41
+ raise ArgumentError.for(:invalid_value), "No block matched the switch value '#{switch_value}'"
40
42
  end
41
43
  end
42
44
 
@@ -1,3 +1,5 @@
1
+ require 'dentaku/exceptions'
2
+
1
3
  module Dentaku
2
4
  module AST
3
5
  class CaseConditional < Node
@@ -7,11 +9,12 @@ module Dentaku
7
9
  def initialize(when_statement, then_statement)
8
10
  @when = when_statement
9
11
  unless @when.is_a?(AST::CaseWhen)
10
- raise 'Expected first argument to be a CaseWhen'
12
+ raise ParseError.for(:node_invalid), 'Expected first argument to be a CaseWhen'
11
13
  end
14
+
12
15
  @then = then_statement
13
16
  unless @then.is_a?(AST::CaseThen)
14
- raise 'Expected second argument to be a CaseThen'
17
+ raise ParseError.for(:node_invalid), 'Expected second argument to be a CaseThen'
15
18
  end
16
19
  end
17
20
 
@@ -38,7 +38,7 @@ module Dentaku
38
38
 
39
39
  if value.is_a?(::String)
40
40
  number = value[/\A-?\d*\.?\d+\z/]
41
- return number.include?('.') ? ::BigDecimal.new(number, DIG) : number.to_i if number
41
+ return number.include?('.') ? BigDecimal(number, DIG) : number.to_i if number
42
42
  end
43
43
 
44
44
  raise Dentaku::ArgumentError.for(:incompatible_type, value: value, for: Numeric),
@@ -19,8 +19,8 @@ module Dentaku
19
19
  key
20
20
  end
21
21
 
22
- def self.expand(h)
23
- h.each_with_object({}) do |(k, v), r|
22
+ def self.expand(hash)
23
+ hash.each_with_object({}) do |(k, v), r|
24
24
  hash_levels = k.to_s.split('.')
25
25
  hash_levels = hash_levels.map(&:to_sym) if k.is_a?(Symbol)
26
26
  child_hash = hash_levels[0...-1].reduce(r) { |h, n| h[n] ||= {} }
@@ -46,6 +46,8 @@ module Dentaku
46
46
  args = Array.new(args_size) { output.pop }.reverse
47
47
 
48
48
  output.push operator.new(*args)
49
+ rescue ::ArgumentError => e
50
+ raise Dentaku::ArgumentError, e.message
49
51
  rescue NodeError => e
50
52
  fail! :node_invalid, operator: operator, child: e.child, expect: e.expect, actual: e.actual
51
53
  end
@@ -111,17 +113,19 @@ module Dentaku
111
113
  open_cases = 0
112
114
  case_end_index = nil
113
115
 
114
- input.each_with_index do |token, index|
115
- if token.category == :case && token.value == :open
116
- open_cases += 1
117
- end
116
+ input.each_with_index do |input_token, index|
117
+ if input_token.category == :case
118
+ if input_token.value == :open
119
+ open_cases += 1
120
+ end
118
121
 
119
- if token.category == :case && token.value == :close
120
- if open_cases > 0
121
- open_cases -= 1
122
- else
123
- case_end_index = index
124
- break
122
+ if input_token.value == :close
123
+ if open_cases > 0
124
+ open_cases -= 1
125
+ else
126
+ case_end_index = index
127
+ break
128
+ end
125
129
  end
126
130
  end
127
131
  end
@@ -129,7 +133,8 @@ module Dentaku
129
133
  subparser = Parser.new(
130
134
  inner_case_inputs,
131
135
  operations: [AST::Case],
132
- arities: [0]
136
+ arities: [0],
137
+ function_registry: @function_registry
133
138
  )
134
139
  subparser.parse
135
140
  output.concat(subparser.output)
@@ -253,6 +258,7 @@ module Dentaku
253
258
  end
254
259
 
255
260
  when :comma
261
+ fail! :invalid_statement if arities.empty?
256
262
  arities[-1] += 1
257
263
  while operations.any? && operations.last != AST::Grouping && operations.last != AST::Array
258
264
  consume
@@ -16,7 +16,7 @@ module Dentaku
16
16
  @range = (@min..@max)
17
17
  end
18
18
 
19
- def | (other_matcher)
19
+ def |(other_matcher)
20
20
  self.class.new(:nomatch, :nomatch, leaf_matchers + other_matcher.leaf_matchers)
21
21
  end
22
22
 
@@ -91,7 +91,7 @@ module Dentaku
91
91
 
92
92
  def numeric
93
93
  new(:numeric, '((?:\d+(\.\d+)?|\.\d+)(?:(e|E)(\+|-)?\d+)?)\b', lambda { |raw|
94
- raw =~ /\./ ? BigDecimal.new(raw) : raw.to_i
94
+ raw =~ /\./ ? BigDecimal(raw) : raw.to_i
95
95
  })
96
96
  end
97
97
 
@@ -12,7 +12,7 @@ module Dentaku
12
12
  def tokenize(string, options = {})
13
13
  @nesting = 0
14
14
  @tokens = []
15
- @aliases = options.fetch(:aliases, Dentaku.aliases)
15
+ @aliases = options.fetch(:aliases, global_aliases)
16
16
  input = strip_comments(string.to_s.dup)
17
17
  input = replace_aliases(input)
18
18
  @case_sensitive = options.fetch(:case_sensitive, false)
@@ -84,6 +84,11 @@ module Dentaku
84
84
 
85
85
  private
86
86
 
87
+ def global_aliases
88
+ return {} unless Dentaku.respond_to?(:aliases)
89
+ Dentaku.aliases
90
+ end
91
+
87
92
  def fail!(reason, **meta)
88
93
  message =
89
94
  case reason
@@ -1,3 +1,3 @@
1
1
  module Dentaku
2
- VERSION = "3.3.0"
2
+ VERSION = "3.3.1"
3
3
  end
@@ -11,7 +11,7 @@ describe Dentaku::AST::Addition do
11
11
 
12
12
  it 'performs addition' do
13
13
  node = described_class.new(five, six)
14
- expect(node.value).to eq 11
14
+ expect(node.value).to eq(11)
15
15
  end
16
16
 
17
17
  it 'requires numeric operands' do
@@ -7,29 +7,29 @@ describe 'Dentaku::AST::And' do
7
7
 
8
8
  it 'returns false if any of the arguments is false' do
9
9
  result = Dentaku('AND(1 = 1, 0 = 1)')
10
- expect(result).to eq false
10
+ expect(result).to eq(false)
11
11
  end
12
12
 
13
13
  it 'supports nested expressions' do
14
14
  result = Dentaku('AND(y = 1, x = 1)', x: 1, y: 2)
15
- expect(result).to eq false
15
+ expect(result).to eq(false)
16
16
  end
17
17
 
18
18
  it 'returns true if all of the arguments are true' do
19
19
  result = Dentaku('AND(1 = 1, "2" = "2", true = true, true)')
20
- expect(result).to eq true
20
+ expect(result).to eq(true)
21
21
  end
22
22
 
23
23
  it 'returns true if all nested AND functions return true' do
24
24
  result = Dentaku('AND(AND(1 = 1), AND(true != false, AND(true)))')
25
- expect(result).to eq true
25
+ expect(result).to eq(true)
26
26
  end
27
27
 
28
28
  it 'raises an error if no arguments are passed' do
29
- expect { calculator.evaluate!('AND()') }.to raise_error(ArgumentError)
29
+ expect { calculator.evaluate!('AND()') }.to raise_error(Dentaku::ArgumentError)
30
30
  end
31
31
 
32
32
  it 'raises an error if a non logical argument is passed' do
33
- expect { calculator.evaluate!('AND("r")') }.to raise_error(ArgumentError)
33
+ expect { calculator.evaluate!('AND("r")') }.to raise_error(Dentaku::ArgumentError)
34
34
  end
35
35
  end
@@ -11,7 +11,7 @@ describe Dentaku::AST::And do
11
11
 
12
12
  it 'performs logical AND' do
13
13
  node = described_class.new(t, f)
14
- expect(node.value).to eq false
14
+ expect(node.value).to eq(false)
15
15
  end
16
16
 
17
17
  it 'requires logical operands' do
@@ -11,29 +11,29 @@ describe Dentaku::AST::Arithmetic do
11
11
  let(:ctx) { {'x' => 1, 'y' => 2} }
12
12
 
13
13
  it 'performs an arithmetic operation with numeric operands' do
14
- expect(add(one, two)).to eq 3
15
- expect(sub(one, two)).to eq -1
16
- expect(mul(one, two)).to eq 2
17
- expect(div(one, two)).to eq 0.5
14
+ expect(add(one, two)).to eq(3)
15
+ expect(sub(one, two)).to eq(-1)
16
+ expect(mul(one, two)).to eq(2)
17
+ expect(div(one, two)).to eq(0.5)
18
18
  end
19
19
 
20
20
  it 'performs an arithmetic operation with one numeric operand and one string operand' do
21
- expect(add(one, x)).to eq 2
22
- expect(sub(one, x)).to eq 0
23
- expect(mul(one, x)).to eq 1
24
- expect(div(one, x)).to eq 1
25
-
26
- expect(add(y, two)).to eq 4
27
- expect(sub(y, two)).to eq 0
28
- expect(mul(y, two)).to eq 4
29
- expect(div(y, two)).to eq 1
21
+ expect(add(one, x)).to eq(2)
22
+ expect(sub(one, x)).to eq(0)
23
+ expect(mul(one, x)).to eq(1)
24
+ expect(div(one, x)).to eq(1)
25
+
26
+ expect(add(y, two)).to eq(4)
27
+ expect(sub(y, two)).to eq(0)
28
+ expect(mul(y, two)).to eq(4)
29
+ expect(div(y, two)).to eq(1)
30
30
  end
31
31
 
32
32
  it 'performs an arithmetic operation with string operands' do
33
- expect(add(x, y)).to eq 3
34
- expect(sub(x, y)).to eq -1
35
- expect(mul(x, y)).to eq 2
36
- expect(div(x, y)).to eq 0.5
33
+ expect(add(x, y)).to eq(3)
34
+ expect(sub(x, y)).to eq(-1)
35
+ expect(mul(x, y)).to eq(2)
36
+ expect(div(x, y)).to eq(0.5)
37
37
  end
38
38
 
39
39
  private
@@ -5,29 +5,29 @@ require 'dentaku'
5
5
  describe 'Dentaku::AST::Function::Avg' do
6
6
  it 'returns the average of an array of Numeric values' do
7
7
  result = Dentaku('AVG(1, x, 1.8)', x: 2.3)
8
- expect(result).to eq 1.7
8
+ expect(result).to eq(1.7)
9
9
  end
10
10
 
11
11
  it 'returns the average of a single entry array of a Numeric value' do
12
12
  result = Dentaku('AVG(x)', x: 2.3)
13
- expect(result).to eq 2.3
13
+ expect(result).to eq(2.3)
14
14
  end
15
15
 
16
16
  it 'returns the average even if a String is passed' do
17
17
  result = Dentaku('AVG(1, x, 1.8)', x: '2.3')
18
- expect(result).to eq 1.7
18
+ expect(result).to eq(1.7)
19
19
  end
20
20
 
21
21
  it 'returns the average even if an array is passed' do
22
22
  result = Dentaku('AVG(1, x, 2.3)', x: [4, 5])
23
- expect(result).to eq 3.075
23
+ expect(result).to eq(3.075)
24
24
  end
25
25
 
26
26
  context 'checking errors' do
27
27
  let(:calculator) { Dentaku::Calculator.new }
28
28
 
29
29
  it 'raises an error if no arguments are passed' do
30
- expect { calculator.evaluate!('AVG()') }.to raise_error(ArgumentError)
30
+ expect { calculator.evaluate!('AVG()') }.to raise_error(Dentaku::ArgumentError)
31
31
  end
32
32
  end
33
33
  end
@@ -5,36 +5,36 @@ require 'dentaku'
5
5
  describe 'Dentaku::AST::Count' do
6
6
  it 'returns the length of an array' do
7
7
  result = Dentaku('COUNT(1, x, 1.8)', x: 2.3)
8
- expect(result).to eq 3
8
+ expect(result).to eq(3)
9
9
  end
10
10
 
11
11
  it 'returns the length of a single number object' do
12
12
  result = Dentaku('COUNT(x)', x: 2.3)
13
- expect(result).to eq 1
13
+ expect(result).to eq(1)
14
14
  end
15
15
 
16
16
  it 'returns the length if a single String is passed' do
17
17
  result = Dentaku('COUNT(x)', x: 'dentaku')
18
- expect(result).to eq 7
18
+ expect(result).to eq(7)
19
19
  end
20
20
 
21
21
  it 'returns the length if an array is passed' do
22
22
  result = Dentaku('COUNT(x)', x: [4, 5])
23
- expect(result).to eq 2
23
+ expect(result).to eq(2)
24
24
  end
25
25
 
26
26
  it 'returns the length if an array with one element is passed' do
27
27
  result = Dentaku('COUNT(x)', x: [4])
28
- expect(result).to eq 1
28
+ expect(result).to eq(1)
29
29
  end
30
30
 
31
31
  it 'returns the length if an array even if it has nested array' do
32
32
  result = Dentaku('COUNT(1, x, 3)', x: [4, 5])
33
- expect(result).to eq 3
33
+ expect(result).to eq(3)
34
34
  end
35
35
 
36
36
  it 'returns the length if an array is passed' do
37
37
  result = Dentaku('COUNT()')
38
- expect(result).to eq 0
38
+ expect(result).to eq(0)
39
39
  end
40
40
  end
@@ -11,7 +11,7 @@ describe Dentaku::AST::Division do
11
11
 
12
12
  it 'performs division' do
13
13
  node = described_class.new(five, six)
14
- expect(node.value.round(4)).to eq 0.8333
14
+ expect(node.value.round(4)).to eq(0.8333)
15
15
  end
16
16
 
17
17
  it 'requires numeric operands' do