dentaku 3.3.0 → 3.3.1

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