eqn 1.6.0 → 1.6.5
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 +5 -5
- data/README.md +2 -2
- data/eqn.gemspec +11 -10
- data/lib/eqn.rb +9 -1
- data/lib/eqn.treetop +7 -6
- data/lib/eqn/calculator.rb +45 -12
- data/lib/eqn/comparation.rb +5 -3
- data/lib/eqn/eqn_node.rb +19 -0
- data/lib/eqn/expression.rb +35 -24
- data/lib/eqn/function.rb +22 -16
- data/lib/eqn/number.rb +25 -23
- data/lib/eqn/parser.rb +8 -16
- data/lib/eqn/terminal.rb +16 -14
- data/lib/eqn/version.rb +1 -1
- metadata +41 -28
- data/lib/eqn/engine.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 807944d76a7626f0a7772757f110600324c9fa63c12aaad04ad68c07c162ea90
|
4
|
+
data.tar.gz: 8debccddd120f9acc3523e6ca8b5a0835823d1c9240177751103b5a886fc7971
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b3efde4aa07b6f310bb23085328186253c2874e1cf91d93cc13dc4289d9a8ea903d38052091a3194fedb8e66af2a74945298009fcf436610a011dfadfe84e8c
|
7
|
+
data.tar.gz: 865205a5958a138849e8e254ce3dcf4145fa10f27d8934a2132e710682919f234f0c021ea6b3b43e08a9f1a7172535cca43d6fa9b8b3066bd08cca4befd24d91
|
data/README.md
CHANGED
@@ -128,7 +128,7 @@ Rounds the number down (i.e. floor function). Optionally, pass a number of decim
|
|
128
128
|
|
129
129
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
130
130
|
|
131
|
-
The gem uses rspec for testing
|
131
|
+
The gem uses rspec for testing and appraisal to test against multiple versions of treetop (the only runtime dependency). From the command line, run `bundle exec appraisal install` to install gems and `bundle exec appraisal rspec` to run the complete test suite. (You can still run `bundle exec rspec` to only test against the latest version of treetop while developing.)
|
132
132
|
|
133
133
|
## Authorship
|
134
134
|
|
@@ -136,7 +136,7 @@ Written by Zach Schneider for [Aha!, the world's #1 product roadmap software](ht
|
|
136
136
|
|
137
137
|
## Contributing
|
138
138
|
|
139
|
-
1. Fork it (
|
139
|
+
1. Fork it ([https://github.com/schneidmaster/eqn/fork](https://github.com/schneidmaster/eqn/fork))
|
140
140
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
141
141
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
142
142
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/eqn.gemspec
CHANGED
@@ -4,7 +4,7 @@ lib = File.expand_path('../lib', __FILE__)
|
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
require 'eqn/version'
|
6
6
|
|
7
|
-
config_files = %w
|
7
|
+
config_files = %w(.rspec .rubocop.yml .ruby-version Appraisals .circleci/config.yml)
|
8
8
|
|
9
9
|
Gem::Specification.new do |spec|
|
10
10
|
spec.name = 'eqn'
|
@@ -12,8 +12,8 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.authors = ['Zach Schneider']
|
13
13
|
spec.email = ['zach@aha.io']
|
14
14
|
|
15
|
-
spec.summary = 'A gem to evaluate
|
16
|
-
spec.description = 'A gem to evaluate
|
15
|
+
spec.summary = 'A gem to evaluate mathematical equations.'
|
16
|
+
spec.description = 'A gem to evaluate mathematical equations. Includes support for variables and functions.'
|
17
17
|
spec.homepage = 'https://github.com/schneidmaster/eqn'
|
18
18
|
spec.license = 'MIT'
|
19
19
|
|
@@ -24,11 +24,12 @@ Gem::Specification.new do |spec|
|
|
24
24
|
|
25
25
|
spec.add_dependency 'treetop', '>= 1.2.0'
|
26
26
|
|
27
|
-
spec.add_development_dependency 'appraisal', '~> 2.
|
28
|
-
spec.add_development_dependency 'bundler', '
|
29
|
-
spec.add_development_dependency 'codeclimate-test-reporter', '~> 0
|
30
|
-
spec.add_development_dependency 'rake', '~>
|
31
|
-
spec.add_development_dependency 'rubocop', '~> 0.
|
32
|
-
spec.add_development_dependency 'rspec', '~>
|
33
|
-
spec.add_development_dependency '
|
27
|
+
spec.add_development_dependency 'appraisal', '~> 2.2.0'
|
28
|
+
spec.add_development_dependency 'bundler', '>= 1.9'
|
29
|
+
spec.add_development_dependency 'codeclimate-test-reporter', '~> 1.0'
|
30
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
31
|
+
spec.add_development_dependency 'rubocop', '~> 0.60'
|
32
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 1.30'
|
33
|
+
spec.add_development_dependency 'rspec', '~> 3.5.0'
|
34
|
+
spec.add_development_dependency 'simplecov', '< 0.18'
|
34
35
|
end
|
data/lib/eqn.rb
CHANGED
@@ -1,2 +1,10 @@
|
|
1
1
|
require 'treetop'
|
2
|
-
|
2
|
+
|
3
|
+
# Load the parser from the Treetop grammar.
|
4
|
+
Treetop.load(File.join(__dir__, 'eqn.treetop'))
|
5
|
+
|
6
|
+
# Load custom eqn syntax node.
|
7
|
+
require File.join(__dir__, 'eqn', 'eqn_node')
|
8
|
+
|
9
|
+
# Load other eqn classes.
|
10
|
+
Dir.glob(File.join(__dir__, 'eqn', '**', '*.rb')).sort.each(&method(:require))
|
data/lib/eqn.treetop
CHANGED
@@ -40,19 +40,19 @@ grammar Eqn
|
|
40
40
|
end
|
41
41
|
|
42
42
|
rule if_func
|
43
|
-
'if' space? '(' comparation ',' expression ',' expression ')' <Eqn::Function::If>
|
43
|
+
('if' / 'IF') space? '(' comparation ',' expression ',' expression ')' <Eqn::Function::If>
|
44
44
|
end
|
45
45
|
|
46
46
|
rule round_func
|
47
|
-
'round' space? '(' expression round_group? ')' <Eqn::Function::Round>
|
47
|
+
('round' / 'ROUND') space? '(' expression round_group? ')' <Eqn::Function::Round>
|
48
48
|
end
|
49
49
|
|
50
50
|
rule roundup_func
|
51
|
-
'roundup' space? '(' expression round_group? ')' <Eqn::Function::RoundUp>
|
51
|
+
('roundup' / 'ROUNDUP') space? '(' expression round_group? ')' <Eqn::Function::RoundUp>
|
52
52
|
end
|
53
53
|
|
54
54
|
rule rounddown_func
|
55
|
-
'rounddown' space? '(' expression round_group? ')' <Eqn::Function::RoundDown>
|
55
|
+
('rounddown' / 'ROUNDDOWN') space? '(' expression round_group? ')' <Eqn::Function::RoundDown>
|
56
56
|
end
|
57
57
|
|
58
58
|
rule round_group
|
@@ -112,7 +112,8 @@ grammar Eqn
|
|
112
112
|
end
|
113
113
|
|
114
114
|
rule sign
|
115
|
-
|
115
|
+
'+'
|
116
|
+
/ '-' <Eqn::Terminal::UnaryMinus>
|
116
117
|
end
|
117
118
|
|
118
119
|
rule digits
|
@@ -126,4 +127,4 @@ grammar Eqn
|
|
126
127
|
rule space
|
127
128
|
("\s" / "\t")*
|
128
129
|
end
|
129
|
-
end
|
130
|
+
end
|
data/lib/eqn/calculator.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
module Eqn
|
2
|
+
# Primary calculator class used for performing calculations or creating eqn instances.
|
2
3
|
class Calculator
|
3
4
|
def initialize(eqn, vars = {})
|
4
5
|
@eqn = eqn
|
@@ -9,36 +10,68 @@ module Eqn
|
|
9
10
|
if key_or_hash.is_a?(Hash)
|
10
11
|
@vars.merge!(key_or_hash)
|
11
12
|
else
|
12
|
-
@vars[key_or_hash.
|
13
|
+
@vars[key_or_hash.to_sym] = value
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
16
17
|
def method_missing(method, *args)
|
17
|
-
if
|
18
|
+
if delegated_method?(method)
|
18
19
|
self.class.send(method, @eqn, @vars)
|
19
|
-
elsif (
|
20
|
-
@vars[
|
21
|
-
elsif (
|
22
|
-
@vars[
|
20
|
+
elsif match_setter?(method)
|
21
|
+
@vars[setter_key(method)] = args.first
|
22
|
+
elsif match_getter?(method)
|
23
|
+
@vars[getter_key(method)]
|
23
24
|
else
|
24
25
|
super
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
|
-
def respond_to_missing?(method)
|
29
|
-
|
29
|
+
def respond_to_missing?(method, _include_private = false)
|
30
|
+
delegated_method?(method) || match_setter?(method) || match_getter?(method) || super
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def delegated_method?(method)
|
36
|
+
%i(calculate calc valid?).include?(method.to_sym)
|
37
|
+
end
|
38
|
+
|
39
|
+
def setter_key(method)
|
40
|
+
match = method.to_s.match(/^[A-Za-z]+=$/)
|
41
|
+
return unless match
|
42
|
+
|
43
|
+
match.to_s.delete('=').to_sym
|
44
|
+
end
|
45
|
+
|
46
|
+
def match_setter?(method)
|
47
|
+
!setter_key(method).nil?
|
48
|
+
end
|
49
|
+
|
50
|
+
def getter_key(method)
|
51
|
+
match = method.to_s.match(/^[A-Za-z]+$/)
|
52
|
+
return if match.nil?
|
53
|
+
|
54
|
+
key = match.to_s.to_sym
|
55
|
+
return unless @vars.key?(key)
|
56
|
+
|
57
|
+
key
|
58
|
+
end
|
59
|
+
|
60
|
+
def match_getter?(method)
|
61
|
+
!getter_key(method).nil?
|
30
62
|
end
|
31
63
|
|
32
64
|
class << self
|
33
|
-
def calculate(
|
34
|
-
result = Parser.parse(
|
65
|
+
def calculate(equation, vars = {})
|
66
|
+
result = Parser.parse(equation).value(vars)
|
35
67
|
raise ZeroDivisionError if result.is_a?(Float) && (result.abs == Float::INFINITY || result.nan?)
|
68
|
+
|
36
69
|
result
|
37
70
|
end
|
38
71
|
alias calc calculate
|
39
72
|
|
40
|
-
def valid?(
|
41
|
-
|
73
|
+
def valid?(equation, vars = {})
|
74
|
+
calculate(equation, vars)
|
42
75
|
true
|
43
76
|
rescue EqnError
|
44
77
|
false
|
data/lib/eqn/comparation.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
module Eqn
|
2
|
-
class
|
2
|
+
# Node class for a comparison between expressions.
|
3
|
+
class Comparation < EqnNode
|
3
4
|
def value(vars = {})
|
4
5
|
val_one = elements.shift.value(vars)
|
5
|
-
if
|
6
|
+
if term?
|
6
7
|
val_one
|
7
8
|
else
|
8
9
|
val_one.send(*elements.shift.value(vars))
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
12
|
-
class
|
13
|
+
# Node class for the operator and expression being compared.
|
14
|
+
class CompGroup < EqnNode
|
13
15
|
def value(vars = {})
|
14
16
|
[elements.shift.value(vars), elements.shift.value(vars)]
|
15
17
|
end
|
data/lib/eqn/eqn_node.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Eqn
|
2
|
+
# Eqn parser node with helper methods for cleaning.
|
3
|
+
class EqnNode < Treetop::Runtime::SyntaxNode
|
4
|
+
def term?
|
5
|
+
elements.nil? || elements.empty?
|
6
|
+
end
|
7
|
+
|
8
|
+
def clean_tree!
|
9
|
+
# Return if node is a terminal.
|
10
|
+
return if term?
|
11
|
+
|
12
|
+
# Delete any cruft syntax nodes.
|
13
|
+
elements.delete_if { |node| !node.is_a?(EqnNode) }
|
14
|
+
|
15
|
+
# Recurse over any elements with their own children.
|
16
|
+
elements.each(&:clean_tree!)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/eqn/expression.rb
CHANGED
@@ -1,38 +1,49 @@
|
|
1
1
|
module Eqn
|
2
|
-
class
|
2
|
+
# Node class for an expression.
|
3
|
+
class Expression < EqnNode
|
3
4
|
def left_associative?
|
4
5
|
elements.any? && elements.last.left_associative?
|
5
6
|
end
|
6
7
|
|
7
|
-
def
|
8
|
-
elements.
|
8
|
+
def value(vars = {})
|
9
|
+
base = elements.shift.value(vars)
|
10
|
+
|
11
|
+
# Aggressively consume left associative operators to maintain associativity.
|
12
|
+
base = consume_while_left_associative(base, vars)
|
13
|
+
|
14
|
+
# Apply next right-associative operator (if any) or return.
|
15
|
+
apply_next_operator(base, vars)
|
9
16
|
end
|
10
17
|
|
11
|
-
|
12
|
-
|
13
|
-
|
18
|
+
private
|
19
|
+
|
20
|
+
def consume_while_left_associative(base, vars)
|
21
|
+
return base unless left_associative?
|
22
|
+
|
23
|
+
base = apply_next_operator(base, vars)
|
24
|
+
consume_while_left_associative(base, vars)
|
25
|
+
end
|
26
|
+
|
27
|
+
def apply_next_operator(base, vars)
|
28
|
+
return base if term?
|
29
|
+
|
30
|
+
left_associative = elements.last.left_associative?
|
31
|
+
op, num_expr = elements.shift.value(vars)
|
32
|
+
if left_associative
|
33
|
+
apply_left_associative(base, vars, op, num_expr)
|
14
34
|
else
|
15
|
-
base
|
16
|
-
|
17
|
-
# Aggressively consume left associative operators to maintain associativity.
|
18
|
-
while left_associative?
|
19
|
-
op, num_expr = elements.shift.value(vars)
|
20
|
-
num_expr_operand = num_expr.elements.shift
|
21
|
-
base = base.send(op, num_expr_operand.value(vars))
|
22
|
-
elements.push num_expr.elements.shift unless num_expr.term?
|
23
|
-
end
|
24
|
-
|
25
|
-
# Apply next right-associative operator (if any) or return.
|
26
|
-
if term?
|
27
|
-
base
|
28
|
-
else
|
29
|
-
op, num_expr = elements.shift.value(vars)
|
30
|
-
base.send(op, num_expr.value(vars))
|
31
|
-
end
|
35
|
+
base.send(op, num_expr.value(vars))
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
35
|
-
|
39
|
+
def apply_left_associative(base, vars, operator, num_expr)
|
40
|
+
num_expr_operand = num_expr.elements.shift
|
41
|
+
elements.push(num_expr.elements.shift) unless num_expr.term?
|
42
|
+
base.send(operator, num_expr_operand.value(vars))
|
43
|
+
end
|
44
|
+
|
45
|
+
# Node class for the operator and latter component of an expression.
|
46
|
+
class ExprGroup < EqnNode
|
36
47
|
def left_associative?
|
37
48
|
elements.first.left_associative?
|
38
49
|
end
|
data/lib/eqn/function.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Eqn
|
2
2
|
module Function
|
3
|
-
class
|
3
|
+
# Node class for the if function.
|
4
|
+
class If < EqnNode
|
4
5
|
def value(vars = {})
|
5
6
|
comp_val = elements.shift.value(vars)
|
6
7
|
ls = elements.shift.value(vars)
|
@@ -10,35 +11,40 @@ module Eqn
|
|
10
11
|
end
|
11
12
|
end
|
12
13
|
|
13
|
-
class
|
14
|
-
|
14
|
+
# Base node class for round functions.
|
15
|
+
class RoundBase < EqnNode
|
16
|
+
def value(vars)
|
15
17
|
value = elements.shift.value(vars)
|
16
18
|
raise ZeroDivisionError if value.is_a?(Float) && (value.abs == Float::INFINITY || value.nan?)
|
17
|
-
|
18
|
-
|
19
|
+
|
20
|
+
if term?
|
21
|
+
value.send(self.class::ROUND_METHOD)
|
19
22
|
else
|
20
|
-
|
21
|
-
(value * 10**decimals).send(fn).to_f / 10**decimals
|
23
|
+
round_to_precision(vars, value)
|
22
24
|
end
|
23
25
|
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def round_to_precision(vars, value)
|
30
|
+
decimals = elements.shift.value(vars)
|
31
|
+
(value * 10**decimals).send(self.class::ROUND_METHOD).to_f / 10**decimals
|
32
|
+
end
|
24
33
|
end
|
25
34
|
|
35
|
+
# Node class for the round function.
|
26
36
|
class Round < RoundBase
|
27
|
-
|
28
|
-
super(:round, vars)
|
29
|
-
end
|
37
|
+
ROUND_METHOD = :round
|
30
38
|
end
|
31
39
|
|
40
|
+
# Node class for the roundup function.
|
32
41
|
class RoundUp < RoundBase
|
33
|
-
|
34
|
-
super(:ceil, vars)
|
35
|
-
end
|
42
|
+
ROUND_METHOD = :ceil
|
36
43
|
end
|
37
44
|
|
45
|
+
# Node class for the rounddown function.
|
38
46
|
class RoundDown < RoundBase
|
39
|
-
|
40
|
-
super(:floor, vars)
|
41
|
-
end
|
47
|
+
ROUND_METHOD = :floor
|
42
48
|
end
|
43
49
|
end
|
44
50
|
end
|
data/lib/eqn/number.rb
CHANGED
@@ -1,43 +1,45 @@
|
|
1
1
|
module Eqn
|
2
|
-
class
|
2
|
+
# Node class for a simple number.
|
3
|
+
class Number < EqnNode
|
3
4
|
def value(vars = {})
|
4
5
|
base = elements.shift.value(vars)
|
5
|
-
# Apply any exponent.
|
6
|
-
base *= elements.shift.value(vars) unless elements.empty?
|
7
|
-
base
|
8
|
-
end
|
9
|
-
|
10
|
-
class SignedNumber < Treetop::Runtime::SyntaxNode
|
11
|
-
def value(vars = {})
|
12
|
-
# Store sign if any.
|
13
|
-
sign_negative = elements.shift.negative? if elements.first.is_a? Terminal::Sign
|
14
6
|
|
15
|
-
|
16
|
-
value = elements.shift.value(vars)
|
7
|
+
return base if term?
|
17
8
|
|
18
|
-
|
19
|
-
|
9
|
+
if instance_of?(Float)
|
10
|
+
# Apply any decimal if a float.
|
11
|
+
base + elements.shift.value(vars)
|
12
|
+
else
|
13
|
+
# Apply any exponent if a simple number.
|
14
|
+
base * elements.shift.value(vars)
|
20
15
|
end
|
21
16
|
end
|
22
17
|
|
23
|
-
class Float <
|
24
|
-
def value(vars = {})
|
25
|
-
base = elements.shift.value(vars)
|
26
|
-
|
27
|
-
# Add any decimal.
|
28
|
-
base += elements.shift.value(vars) unless elements.empty?
|
18
|
+
class Float < Number; end
|
29
19
|
|
30
|
-
|
20
|
+
# Node class for a signed number.
|
21
|
+
class SignedNumber < EqnNode
|
22
|
+
def value(vars = {})
|
23
|
+
first_element = elements.shift
|
24
|
+
# If first element is unary minus, negate the following value.
|
25
|
+
# Otherwise, simply return the positive value.
|
26
|
+
if first_element.is_a?(Terminal::UnaryMinus)
|
27
|
+
-elements.shift.value(vars)
|
28
|
+
else
|
29
|
+
first_element.value(vars)
|
30
|
+
end
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
class
|
34
|
+
# Node class for the decimal part of a non-integer.
|
35
|
+
class Decimal < EqnNode
|
35
36
|
def value(_vars = {})
|
36
37
|
elements.shift.dec_value
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
40
|
-
class
|
41
|
+
# Node class for the exponent part of a number.
|
42
|
+
class Exponent < EqnNode
|
41
43
|
def value(vars = {})
|
42
44
|
10**elements.shift.value(vars)
|
43
45
|
end
|
data/lib/eqn/parser.rb
CHANGED
@@ -1,27 +1,19 @@
|
|
1
1
|
module Eqn
|
2
|
+
# Primary parser class to convert a string equation to a tree of nodes.
|
2
3
|
class Parser
|
3
|
-
# Load the Treetop grammar from the grammar.
|
4
|
-
Treetop.load(File.join(File.dirname(__dir__), 'eqn.treetop'))
|
5
|
-
@@parser = EqnParser.new
|
6
|
-
|
7
4
|
class << self
|
8
|
-
def parse(
|
9
|
-
|
10
|
-
|
5
|
+
def parse(equation)
|
6
|
+
parser = EqnParser.new
|
7
|
+
|
8
|
+
# Pass the equation over to the parser instance.
|
9
|
+
root_node = parser.parse(equation)
|
11
10
|
|
12
11
|
# Raise any errors.
|
13
|
-
raise ParseError, "Parse error at offset: #{
|
12
|
+
raise ParseError, "Parse error at offset: #{parser.index} -- #{parser.failure_reason}" if root_node.nil?
|
14
13
|
|
15
14
|
# Remove extraneous nodes and return tree.
|
16
|
-
clean_tree
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
15
|
+
root_node.clean_tree!
|
20
16
|
|
21
|
-
def clean_tree(root_node)
|
22
|
-
return if root_node.elements.nil?
|
23
|
-
root_node.elements.delete_if { |node| node.class == Treetop::Runtime::SyntaxNode }
|
24
|
-
root_node.elements.each { |node| clean_tree(node) }
|
25
17
|
root_node
|
26
18
|
end
|
27
19
|
end
|
data/lib/eqn/terminal.rb
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
module Eqn
|
2
2
|
module Terminal
|
3
|
-
class
|
3
|
+
# Node class for a variable.
|
4
|
+
class Variable < EqnNode
|
4
5
|
def value(vars = {})
|
5
|
-
val = vars[text_value.
|
6
|
+
val = vars[text_value.to_sym]
|
6
7
|
raise NoVariableValueError, "No value given for: #{text_value}" unless val
|
7
|
-
raise NonNumericVariableError, "Variable #{text_value} value is nonnumeric: #{val}" unless val.is_a?
|
8
|
+
raise NonNumericVariableError, "Variable #{text_value} value is nonnumeric: #{val}" unless val.is_a?(Numeric)
|
9
|
+
|
8
10
|
val
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
12
|
-
class
|
14
|
+
# Node class for a group of numbers.
|
15
|
+
class Digits < EqnNode
|
13
16
|
def dec_value
|
14
17
|
".#{text_value}".to_f
|
15
18
|
end
|
@@ -19,28 +22,27 @@ module Eqn
|
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
22
|
-
class
|
23
|
-
|
24
|
-
text_value == '-'
|
25
|
-
end
|
26
|
-
end
|
25
|
+
# Node class for a unary minus.
|
26
|
+
class UnaryMinus < EqnNode; end
|
27
27
|
|
28
|
-
class
|
28
|
+
# Node class for an operator.
|
29
|
+
class Op < EqnNode
|
29
30
|
def left_associative?
|
30
|
-
is_a?
|
31
|
+
is_a?(LeftAssociativeOp)
|
31
32
|
end
|
32
33
|
|
33
34
|
def value(_vars = {})
|
34
|
-
text_value == '^' ? :** : text_value.
|
35
|
+
text_value == '^' ? :** : text_value.to_sym
|
35
36
|
end
|
36
37
|
|
37
38
|
class LeftAssociativeOp < Op; end
|
38
39
|
class RightAssociativeOp < Op; end
|
39
40
|
end
|
40
41
|
|
41
|
-
class
|
42
|
+
# Node class for a comparation operator.
|
43
|
+
class CompOp < EqnNode
|
42
44
|
def value(_vars = {})
|
43
|
-
text_value == '=' ? :== : text_value.
|
45
|
+
text_value == '=' ? :== : text_value.to_sym
|
44
46
|
end
|
45
47
|
end
|
46
48
|
end
|
data/lib/eqn/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eqn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.6.
|
4
|
+
version: 1.6.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zach Schneider
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: treetop
|
@@ -30,99 +30,113 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.
|
33
|
+
version: 2.2.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 2.
|
40
|
+
version: 2.2.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '1.
|
47
|
+
version: '1.9'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '1.
|
54
|
+
version: '1.9'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: codeclimate-test-reporter
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0
|
61
|
+
version: '1.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 0
|
68
|
+
version: '1.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '13.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '13.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rubocop
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '0.
|
89
|
+
version: '0.60'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '0.
|
96
|
+
version: '0.60'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name: rspec
|
98
|
+
name: rubocop-rspec
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
103
|
+
version: '1.30'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
110
|
+
version: '1.30'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: rspec
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
117
|
+
version: 3.5.0
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
125
|
-
|
124
|
+
version: 3.5.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: simplecov
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "<"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0.18'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "<"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.18'
|
139
|
+
description: A gem to evaluate mathematical equations. Includes support for variables
|
126
140
|
and functions.
|
127
141
|
email:
|
128
142
|
- zach@aha.io
|
@@ -142,7 +156,7 @@ files:
|
|
142
156
|
- lib/eqn.treetop
|
143
157
|
- lib/eqn/calculator.rb
|
144
158
|
- lib/eqn/comparation.rb
|
145
|
-
- lib/eqn/
|
159
|
+
- lib/eqn/eqn_node.rb
|
146
160
|
- lib/eqn/errors.rb
|
147
161
|
- lib/eqn/expression.rb
|
148
162
|
- lib/eqn/function.rb
|
@@ -154,7 +168,7 @@ homepage: https://github.com/schneidmaster/eqn
|
|
154
168
|
licenses:
|
155
169
|
- MIT
|
156
170
|
metadata: {}
|
157
|
-
post_install_message:
|
171
|
+
post_install_message:
|
158
172
|
rdoc_options: []
|
159
173
|
require_paths:
|
160
174
|
- lib
|
@@ -169,9 +183,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
169
183
|
- !ruby/object:Gem::Version
|
170
184
|
version: '0'
|
171
185
|
requirements: []
|
172
|
-
|
173
|
-
|
174
|
-
signing_key:
|
186
|
+
rubygems_version: 3.0.3
|
187
|
+
signing_key:
|
175
188
|
specification_version: 4
|
176
|
-
summary: A gem to evaluate
|
189
|
+
summary: A gem to evaluate mathematical equations.
|
177
190
|
test_files: []
|