eqn 1.3.2 → 1.4.0

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