eqn 1.3.2 → 1.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1719c42c8c6c2969cbc5bc1895317205b233a23b
4
- data.tar.gz: c3917e3e216c4c5cb6738886d505bde0f2ab73b6
3
+ metadata.gz: d070fa9a192c3c584f4d91b4adb0b8e7500f8cb5
4
+ data.tar.gz: a88cd4517b3978cae22afc0efa8e57cd4ad57d9b
5
5
  SHA512:
6
- metadata.gz: 7bc8f654be594c43376da76c350026ffc6be2078047b334aa8d5ab3fad3b04e5d86bab77f9a7d6d9a6ea7c895eeb8dd314173260d5982132a7cfd1d288a13de1
7
- data.tar.gz: 28202b1fa04f0ee38140bf772699b68dd2643e8f3f8506fe38f693baf294ae82533219379b87c91b117003fd33bd76f7e5ffbd996e887dee9b0d28438f49a20a
6
+ metadata.gz: 98a4e10833eef688a1ade5d4eb2ebde63df3555c6305216c8e5aa58904656b0b2a21639c91bad1a298b3dce0f13a4017db68eff7bc3c0fa6b1b12e9d89e44a04
7
+ data.tar.gz: cf9c913e5e3229ce7258e9babf4d1e40dc807d4c5dc4e0ee3dcf78ebea3fcbe328e8adcff6dddbbfd3b9022586e0374f102893983d027245f98d9a85556eb52f
data/.gitignore CHANGED
@@ -1,9 +1,4 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
1
+ .bundle
2
+ coverage
3
+ Gemfile.lock
4
+ pkg
data/README.md CHANGED
@@ -58,6 +58,15 @@ Eqn supports dynamically inserting values into an equation. Variables are passed
58
58
  $ Eqn::Calculator.calc('if(a > 10, b, c)', a: 15, b: 1, c: 0) # see below for function documentation
59
59
  # => 1
60
60
 
61
+ If you need distinct equations with variable sets, you can instantiate separate instances:
62
+
63
+ $ calc = Eqn::Calculator.new('1 + abc', abc: 2.0)
64
+ $ calc.calc
65
+ # => 3.0
66
+ $ calc_two = Eqn::Calculator.new('1 + abc', abc: 5.0)
67
+ $ calc_two.calc
68
+ # => 6.0
69
+
61
70
  ### Functions
62
71
 
63
72
  Eqn presently supports four functions:
data/bin/console CHANGED
@@ -3,12 +3,5 @@
3
3
  require 'bundler/setup'
4
4
  require 'eqn'
5
5
 
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
6
  require 'irb'
14
7
  IRB.start
data/lib/eqn.rb CHANGED
@@ -1,5 +1,2 @@
1
1
  require 'treetop'
2
- require 'eqn/version'
3
- require 'eqn/parser'
4
- require 'eqn/calculator'
5
- require 'eqn/engine' if defined? Rails
2
+ Dir.glob File.join(__dir__, 'eqn', '**', '*.rb'), &method(:require)
data/lib/eqn.treetop CHANGED
@@ -84,27 +84,27 @@ grammar Eqn
84
84
  end
85
85
 
86
86
  rule pow_op
87
- '^' <Eqn::Terminal::Op::Pow>
87
+ '^' <Eqn::Terminal::Op::RightAssociativeOp>
88
88
  end
89
89
 
90
90
  rule muldiv_op
91
- '*' <Eqn::Terminal::Op::Mul>
92
- / '/' <Eqn::Terminal::Op::Div>
91
+ '*' <Eqn::Terminal::Op::RightAssociativeOp>
92
+ / '/' <Eqn::Terminal::Op::LeftAssociativeOp>
93
93
  end
94
94
 
95
95
  rule addsub_op
96
- '+' <Eqn::Terminal::Op::Add>
97
- / '-' <Eqn::Terminal::Op::Sub>
96
+ '+' <Eqn::Terminal::Op::RightAssociativeOp>
97
+ / '-' <Eqn::Terminal::Op::LeftAssociativeOp>
98
98
  end
99
99
 
100
100
  rule comp_op
101
- '<=' <Eqn::Terminal::CompOp::Lte>
102
- / '>=' <Eqn::Terminal::CompOp::Gte>
103
- / '<' <Eqn::Terminal::CompOp::Lt>
104
- / '>' <Eqn::Terminal::CompOp::Gt>
105
- / '==' <Eqn::Terminal::CompOp::Eq>
106
- / '=' <Eqn::Terminal::CompOp::Eq>
107
- / '!=' <Eqn::Terminal::CompOp::Neq>
101
+ '<=' <Eqn::Terminal::CompOp>
102
+ / '>=' <Eqn::Terminal::CompOp>
103
+ / '<' <Eqn::Terminal::CompOp>
104
+ / '>' <Eqn::Terminal::CompOp>
105
+ / '==' <Eqn::Terminal::CompOp>
106
+ / '=' <Eqn::Terminal::CompOp>
107
+ / '!=' <Eqn::Terminal::CompOp>
108
108
  end
109
109
 
110
110
  rule exp
@@ -1,16 +1,32 @@
1
1
  module Eqn
2
2
  class Calculator
3
+ def initialize(eqn, vars = {})
4
+ @eqn = eqn
5
+ @vars = vars
6
+ end
7
+
8
+ def set(key, value)
9
+ @vars[key.intern] = value
10
+ end
11
+
12
+ def method_missing(method)
13
+ super unless %i(calculate calc valid?).include?(method)
14
+ self.class.send(method, @eqn, @vars)
15
+ end
16
+
3
17
  class << self
4
- def calc(data, vars = {})
18
+ def calculate(data, vars = {})
19
+ @@cache_vars = @@vars if defined?(@@vars)
5
20
  @@vars = vars
6
21
  begin
7
22
  result = Parser.parse(data).value
8
- fail ZeroDivisionError if result.is_a?(Float) && (result.abs == Float::INFINITY || result.nan?)
23
+ raise ZeroDivisionError if result.is_a?(Float) && (result.abs == Float::INFINITY || result.nan?)
9
24
  result
10
25
  ensure
11
- @@vars = nil
26
+ @@vars = defined?(@@cache_vars) ? @@cache_vars : nil
12
27
  end
13
28
  end
29
+ alias calc calculate
14
30
 
15
31
  def valid?(data, vars = {})
16
32
  calc(data, vars)
@@ -1,18 +1,15 @@
1
1
  module Eqn
2
- class Node < Treetop::Runtime::SyntaxNode; end
3
-
4
- class Comparation < Node
2
+ class Comparation < Treetop::Runtime::SyntaxNode
5
3
  def value
6
4
  val_one = elements.shift.value
7
5
  if elements.empty?
8
6
  val_one
9
7
  else
10
- op, val_two = elements.shift.value
11
- val_one.send(op, val_two)
8
+ val_one.send(*elements.shift.value)
12
9
  end
13
10
  end
14
11
 
15
- class CompGroup < Node
12
+ class CompGroup < Treetop::Runtime::SyntaxNode
16
13
  def value
17
14
  [elements.shift.value, elements.shift.value]
18
15
  end
data/lib/eqn/engine.rb CHANGED
@@ -1,7 +1,11 @@
1
1
  module Eqn
2
- class Engine < ::Rails::Engine
3
- initializer 'eqn' do
4
- config.autoload_paths += Dir["#{config.root}/lib/**/"]
2
+ if defined? Rails
3
+ # :nocov:
4
+ class Engine < ::Rails::Engine
5
+ initializer 'eqn' do
6
+ config.autoload_paths += Dir["#{config.root}/lib/**/"]
7
+ end
5
8
  end
9
+ # :nocov:
6
10
  end
7
11
  end
@@ -1,7 +1,5 @@
1
1
  module Eqn
2
- class Node < Treetop::Runtime::SyntaxNode; end
3
-
4
- class Expression < Node
2
+ class Expression < Treetop::Runtime::SyntaxNode
5
3
  def left_associative?
6
4
  elements.any? && elements.last.left_associative?
7
5
  end
@@ -34,7 +32,7 @@ module Eqn
34
32
  end
35
33
  end
36
34
 
37
- class ExprGroup < Node
35
+ class ExprGroup < Treetop::Runtime::SyntaxNode
38
36
  def left_associative?
39
37
  elements.first.left_associative?
40
38
  end
data/lib/eqn/function.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  module Eqn
2
- class Node < Treetop::Runtime::SyntaxNode; end
3
-
4
2
  module Function
5
- class If < Node
3
+ class If < Treetop::Runtime::SyntaxNode
6
4
  def value
7
5
  comp_val = elements.shift.value
8
6
  ls = elements.shift.value
@@ -12,41 +10,34 @@ module Eqn
12
10
  end
13
11
  end
14
12
 
15
- class Round < Node
16
- def value
13
+ class RoundBase < Treetop::Runtime::SyntaxNode
14
+ def value(fn)
17
15
  value = elements.shift.value
18
- fail ZeroDivisionError if value.is_a?(Float) && (value.abs == Float::INFINITY || value.nan?)
16
+ raise ZeroDivisionError if value.is_a?(Float) && (value.abs == Float::INFINITY || value.nan?)
19
17
  if elements.empty?
20
- value.round
18
+ value.send(fn)
21
19
  else
22
- value.round(elements.shift.value)
20
+ decimals = elements.shift.value
21
+ (value * 10**decimals).send(fn).to_f / 10**decimals
23
22
  end
24
23
  end
25
24
  end
26
25
 
27
- class RoundUp < Node
26
+ class Round < RoundBase
28
27
  def value
29
- value = elements.shift.value
30
- fail ZeroDivisionError if value.is_a?(Float) && (value.abs == Float::INFINITY || value.nan?)
31
- if elements.empty?
32
- value.ceil
33
- else
34
- decimals = elements.shift.value
35
- (value * 10**decimals).ceil.to_f / 10**decimals
36
- end
28
+ super(:round)
37
29
  end
38
30
  end
39
31
 
40
- class RoundDown < Node
32
+ class RoundUp < RoundBase
41
33
  def value
42
- value = elements.shift.value
43
- fail ZeroDivisionError if value.is_a?(Float) && (value.abs == Float::INFINITY || value.nan?)
44
- if elements.empty?
45
- value.floor
46
- else
47
- decimals = elements.shift.value
48
- (value * 10**decimals).floor.to_f / 10**decimals
49
- end
34
+ super(:ceil)
35
+ end
36
+ end
37
+
38
+ class RoundDown < RoundBase
39
+ def value
40
+ super(:floor)
50
41
  end
51
42
  end
52
43
  end
data/lib/eqn/number.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  module Eqn
2
- class Node < Treetop::Runtime::SyntaxNode; end
3
-
4
- class Number < Node
2
+ class Number < Treetop::Runtime::SyntaxNode
5
3
  def value
6
4
  base = elements.shift.value
7
5
  # Apply any exponent.
@@ -9,7 +7,7 @@ module Eqn
9
7
  base
10
8
  end
11
9
 
12
- class SignedNumber < Node
10
+ class SignedNumber < Treetop::Runtime::SyntaxNode
13
11
  def value
14
12
  # Store sign if any.
15
13
  sign_negative = elements.shift.negative? if elements.first.is_a? Terminal::Sign
@@ -22,7 +20,7 @@ module Eqn
22
20
  end
23
21
  end
24
22
 
25
- class Float < Node
23
+ class Float < Treetop::Runtime::SyntaxNode
26
24
  def value
27
25
  base = elements.shift.value
28
26
 
@@ -33,13 +31,13 @@ module Eqn
33
31
  end
34
32
  end
35
33
 
36
- class Decimal < Node
34
+ class Decimal < Treetop::Runtime::SyntaxNode
37
35
  def value
38
36
  elements.shift.dec_value
39
37
  end
40
38
  end
41
39
 
42
- class Exponent < Node
40
+ class Exponent < Treetop::Runtime::SyntaxNode
43
41
  def value
44
42
  10**elements.shift.value
45
43
  end
data/lib/eqn/parser.rb CHANGED
@@ -1,33 +1,29 @@
1
- require 'eqn/comparation'
2
- require 'eqn/errors'
3
- require 'eqn/expression'
4
- require 'eqn/function'
5
- require 'eqn/number'
6
- require 'eqn/terminal'
7
-
8
1
  module Eqn
9
2
  class Parser
10
3
  # Load the Treetop grammar from the grammar.
11
4
  Treetop.load(File.join(File.dirname(__dir__), 'eqn.treetop'))
12
5
  @@parser = EqnParser.new
13
6
 
14
- def self.parse(data)
15
- # Pass the data over to the parser instance.
16
- tree = @@parser.parse(data.downcase)
7
+ class << self
8
+ def parse(data)
9
+ # Pass the data over to the parser instance.
10
+ tree = @@parser.parse(data.downcase)
17
11
 
18
- # Raise any errors.
19
- fail ParseError, "Parse error at offset: #{@@parser.index}" + @@parser.failure_reason if tree.nil?
12
+ # Raise any errors.
13
+ raise ParseError, "Parse error at offset: #{@@parser.index}" + @@parser.failure_reason if tree.nil?
20
14
 
21
- # Remove extraneous nodes and return tree.
22
- clean_tree(tree)
23
- end
15
+ # Remove extraneous nodes and return tree.
16
+ clean_tree(tree)
17
+ end
18
+
19
+ private
24
20
 
25
- def self.clean_tree(root_node)
26
- return if root_node.elements.nil?
27
- root_node.elements.delete_if { |node| node.class.name == 'Treetop::Runtime::SyntaxNode' }
28
- root_node.elements.each { |node| clean_tree(node) }
29
- root_node
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
+ root_node
26
+ end
30
27
  end
31
- private_class_method :clean_tree
32
28
  end
33
29
  end
data/lib/eqn/terminal.rb CHANGED
@@ -1,20 +1,15 @@
1
1
  module Eqn
2
2
  module Terminal
3
- class Node < Treetop::Runtime::SyntaxNode; end
4
-
5
- class Variable < Node
3
+ class Variable < Treetop::Runtime::SyntaxNode
6
4
  def value
7
- unless Eqn::Calculator.class_variable_get(:@@vars).key? text_value.intern
8
- fail NoVariableValueError, "No value given for: #{text_value}"
9
- end
10
- unless Eqn::Calculator.class_variable_get(:@@vars)[text_value.intern].is_a? Numeric
11
- fail NonNumericVariableError, "Variable #{text_value} value is nonnumeric: #{Eqn::Calculator.class_variable_get(:@@vars)[text_value.intern]}"
12
- end
13
- Eqn::Calculator.class_variable_get(:@@vars)[text_value.intern]
5
+ val = Eqn::Calculator.class_variable_get(:@@vars)[text_value.intern]
6
+ raise NoVariableValueError, "No value given for: #{text_value}" unless val
7
+ raise NonNumericVariableError, "Variable #{text_value} value is nonnumeric: #{val}" unless val.is_a? Numeric
8
+ val
14
9
  end
15
10
  end
16
11
 
17
- class Digits < Node
12
+ class Digits < Treetop::Runtime::SyntaxNode
18
13
  def dec_value
19
14
  ".#{text_value}".to_f
20
15
  end
@@ -24,99 +19,28 @@ module Eqn
24
19
  end
25
20
  end
26
21
 
27
- class Sign < Node
22
+ class Sign < Treetop::Runtime::SyntaxNode
28
23
  def negative?
29
24
  text_value == '-'
30
25
  end
31
26
  end
32
27
 
33
- class Op < Node
34
- class Add < Node
35
- def left_associative?
36
- false
37
- end
38
-
39
- def value
40
- '+'
41
- end
42
- end
43
-
44
- class Sub < Node
45
- def left_associative?
46
- true
47
- end
48
-
49
- def value
50
- '-'
51
- end
52
- end
53
-
54
- class Mul < Node
55
- def left_associative?
56
- false
57
- end
58
-
59
- def value
60
- '*'
61
- end
28
+ class Op < Treetop::Runtime::SyntaxNode
29
+ def left_associative?
30
+ is_a? LeftAssociativeOp
62
31
  end
63
32
 
64
- class Div < Node
65
- def left_associative?
66
- true
67
- end
68
-
69
- def value
70
- '/'
71
- end
33
+ def value
34
+ text_value == '^' ? :** : text_value.intern
72
35
  end
73
36
 
74
- class Pow < Node
75
- def left_associative?
76
- false
77
- end
78
-
79
- def value
80
- '**'
81
- end
82
- end
37
+ class LeftAssociativeOp < Op; end
38
+ class RightAssociativeOp < Op; end
83
39
  end
84
40
 
85
- class CompOp < Node
86
- class Lt < Node
87
- def value
88
- '<'
89
- end
90
- end
91
-
92
- class Gt < Node
93
- def value
94
- '>'
95
- end
96
- end
97
-
98
- class Lte < Node
99
- def value
100
- '<='
101
- end
102
- end
103
-
104
- class Gte < Node
105
- def value
106
- '>='
107
- end
108
- end
109
-
110
- class Eq < Node
111
- def value
112
- '=='
113
- end
114
- end
115
-
116
- class Neq < Node
117
- def value
118
- '!='
119
- end
41
+ class CompOp < Treetop::Runtime::SyntaxNode
42
+ def value
43
+ text_value == '=' ? :== : text_value.intern
120
44
  end
121
45
  end
122
46
  end
data/lib/eqn/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Eqn
2
- VERSION = '1.3.2'
2
+ VERSION = '1.4.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,111 +1,111 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eqn
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Schneider
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-10-26 00:00:00.000000000 Z
11
+ date: 2016-05-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: treetop
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: 1.4.14
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.4.14
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.8'
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
40
  version: '1.8'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: codeclimate-test-reporter
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: 0.4.7
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
54
  version: 0.4.7
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: '10.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
68
  version: '10.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rubocop
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0.31'
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
82
  version: '0.31'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ~>
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
89
  version: 3.2.0
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
96
  version: 3.2.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: simplecov
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ~>
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
103
  version: 0.10.0
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
110
  version: 0.10.0
111
111
  description: A gem to evaluate numerical equations. Includes support for variables
@@ -116,10 +116,10 @@ executables: []
116
116
  extensions: []
117
117
  extra_rdoc_files: []
118
118
  files:
119
- - .gitignore
120
- - .rspec
121
- - .rubocop.yml
122
- - .ruby-version
119
+ - ".gitignore"
120
+ - ".rspec"
121
+ - ".rubocop.yml"
122
+ - ".ruby-version"
123
123
  - Gemfile
124
124
  - LICENSE.txt
125
125
  - README.md
@@ -149,17 +149,17 @@ require_paths:
149
149
  - lib
150
150
  required_ruby_version: !ruby/object:Gem::Requirement
151
151
  requirements:
152
- - - '>='
152
+ - - ">="
153
153
  - !ruby/object:Gem::Version
154
154
  version: '0'
155
155
  required_rubygems_version: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - '>='
157
+ - - ">="
158
158
  - !ruby/object:Gem::Version
159
159
  version: '0'
160
160
  requirements: []
161
161
  rubyforge_project:
162
- rubygems_version: 2.4.6
162
+ rubygems_version: 2.5.1
163
163
  signing_key:
164
164
  specification_version: 4
165
165
  summary: A gem to evaluate numerical equations.