little_math_pet 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2-p0@LittleMathPet
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "bundler", "~> 1.0.0"
10
+ gem "jeweler", "~> 1.5.2"
11
+ gem "rspec", "~> 2.5.0"
12
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,26 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ git (1.2.5)
6
+ jeweler (1.5.2)
7
+ bundler (~> 1.0.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ rake (0.8.7)
11
+ rspec (2.5.0)
12
+ rspec-core (~> 2.5.0)
13
+ rspec-expectations (~> 2.5.0)
14
+ rspec-mocks (~> 2.5.0)
15
+ rspec-core (2.5.1)
16
+ rspec-expectations (2.5.0)
17
+ diff-lcs (~> 1.1.2)
18
+ rspec-mocks (2.5.0)
19
+
20
+ PLATFORMS
21
+ ruby
22
+
23
+ DEPENDENCIES
24
+ bundler (~> 1.0.0)
25
+ jeweler (~> 1.5.2)
26
+ rspec (~> 2.5.0)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Kostas Karachalios
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,34 @@
1
+ = Little math pet
2
+
3
+ This is a simple math parser. It always returns in Float.
4
+
5
+ 0.1 - It supports addition/subtraction, multiplication/division, exponents and brackets in their correct order.
6
+
7
+ == Examples
8
+
9
+ LittleMathPet.new("5*12+8").calc # => 68.0
10
+ LittleMathPet.new("5*(12+8)").calc # => 100.0
11
+
12
+ It also can handle variables
13
+ LittleMathPet.new("5*a+8").calc(:a => 4) # => 28.0
14
+ LittleMathPet.new("a*b+c^d").calc(:a => 4, :b => 3, :c => 2, :d => 5) # => 44.0
15
+
16
+ == Syntax
17
+
18
+ Mostly ruby (+ - * / ** and ()) but can also accept : for division, ^ for exponents and [] for bracketing. It will also not mind about spaces.
19
+
20
+ == Contributing to little-math-pet
21
+
22
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
23
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
24
+ * Fork the project
25
+ * Start a feature/bugfix branch
26
+ * Commit and push until you are happy with your contribution
27
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
28
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
29
+
30
+ == Copyright
31
+
32
+ Copyright (c) 2011 Kostas Karachalios. See LICENSE.txt for
33
+ further details.
34
+
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "little-math-pet"
16
+ gem.homepage = "http://github.com/vrinek/little-math-pet"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Parses math expressions and returns the result}
19
+ gem.description = %Q{LittleMathPet understands simple math expressions in string format with mutliple variables and returns the result of the expression}
20
+ gem.email = "kostas.karachalios@me.com"
21
+ gem.authors = ["Kostas Karachalios"]
22
+ end
23
+ Jeweler::RubygemsDotOrgTasks.new
24
+
25
+ require 'rake/rdoctask'
26
+ Rake::RDocTask.new do |rdoc|
27
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
28
+
29
+ rdoc.rdoc_dir = 'rdoc'
30
+ rdoc.title = "little-math-pet #{version}"
31
+ rdoc.rdoc_files.include('README*')
32
+ rdoc.rdoc_files.include('lib/**/*.rb')
33
+ end
34
+
35
+ require 'rspec/core'
36
+ require 'rspec/core/rake_task'
37
+ RSpec::Core::RakeTask.new(:spec) do |spec|
38
+ spec.pattern = FileList['spec/**/*_spec.rb']
39
+ end
40
+
41
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
42
+ spec.pattern = 'spec/**/*_spec.rb'
43
+ spec.rcov = true
44
+ end
45
+
46
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.3
@@ -0,0 +1,113 @@
1
+ class LittleMathPet
2
+ # This is used to match numbers in regular expressions
3
+ NUMBER_RX = '([\+\-]?\d+(\.\d+)?)'
4
+
5
+ # This is used to match mathematical signs in regular expressions
6
+ SIGN_RX = '([\+\-\/\*\^])'
7
+
8
+ # The proper math order (power, multiplication/division and addiction/subtraction)
9
+ MATH_ORDER = [%w[^], %w[* /], %w[+ -]]
10
+
11
+ # The processes to use for the math
12
+ MATH_PROCS = {
13
+ '-' => Proc.new{|a,b| a-b},
14
+ '+' => Proc.new{|a,b| a+b},
15
+ '*' => Proc.new{|a,b| a*b},
16
+ '/' => Proc.new{|a,b| a/b},
17
+ '^' => Proc.new{|a,b| a**b}
18
+ }
19
+
20
+ def initialize(math_expression)
21
+ @math = math_expression
22
+ @math = @math.gsub(/\s/, '') # no spaces allowed
23
+
24
+ @math = @math.gsub(/\:/, '/') # 4:2 -> 4/2
25
+ @math = @math.gsub(/\*\*/, '^') # 4**2 -> 4^2 to make it easier to differantiate from 4*2
26
+
27
+ @math = @math.gsub(/\[/, '(')
28
+ @math = @math.gsub(/\]/, ')')
29
+ end
30
+
31
+ def calc(variables = {})
32
+ unless variables.empty?
33
+ variables.each do |letter, number|
34
+ @math.gsub!(letter.to_s, number.to_s)
35
+ end
36
+ end
37
+
38
+ raise 'Invalid math expression' unless @math[/^[\d\-\+\/\*\^\.\(\)]+$/]
39
+
40
+ do_math(@math)
41
+ end
42
+
43
+ private
44
+
45
+ # This is the top level method which deals with the various cases
46
+ def do_math(math)
47
+ case math
48
+ when /\([^\)]+\)/
49
+ math = math.gsub(/\(([^\)]+)\)/) do |match|
50
+ do_math($1)
51
+ end
52
+
53
+ do_math(math)
54
+ when /^#{NUMBER_RX}(#{SIGN_RX}#{NUMBER_RX})+$/
55
+ solve_math(math)
56
+ when /^#{NUMBER_RX}$/
57
+ math.to_f
58
+ when /^#{SIGN_RX}$/
59
+ math
60
+ when ""
61
+ # this appears when '-5' gets split to ['', '-', '5']
62
+ 0.0
63
+ else
64
+ raise 'Invalid math expression'
65
+ end
66
+ end
67
+
68
+ # This is the actual solver that invokes the marh Procs
69
+ def solve_math(math)
70
+ parts = math.split(/#{SIGN_RX}/)
71
+
72
+ until parts.all?{|p| p.to_s[/^#{SIGN_RX}$/] or p.is_a?(Float)}
73
+ parts.collect! do |part|
74
+ do_math(part)
75
+ end
76
+ end
77
+
78
+ # reduces the math expression one process at a time until we have a number
79
+ until parts.length == 1
80
+ i = 0
81
+ proc_positions = parts.inject({}) do |hash, part|
82
+ if part.to_s[/^#{SIGN_RX}$/]
83
+ hash[part] ||= i
84
+ end
85
+ i += 1
86
+
87
+ hash
88
+ end
89
+
90
+ next_proc = nil
91
+ next_position = nil
92
+ MATH_ORDER.each do |symbols|
93
+ unless (symbols & proc_positions.keys).empty? or next_proc
94
+ next_proc = (symbols & proc_positions.keys).min_by do |p|
95
+ proc_positions[p]
96
+ end
97
+ next_position = proc_positions[next_proc]
98
+ end
99
+ end
100
+
101
+ if parts[next_position][/^#{SIGN_RX}$/]
102
+ result = MATH_PROCS[parts[next_position]].call((parts[next_position-1] || 0), parts[next_position+1])
103
+ parts[next_position-1] = parts[next_position+1] = nil
104
+ parts[next_position] = result
105
+ parts.compact!
106
+ else
107
+ raise 'Invalid math expression'
108
+ end
109
+ end
110
+
111
+ return parts.first
112
+ end
113
+ end
@@ -0,0 +1,61 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{little_math_pet}
8
+ s.version = "0.1.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Kostas Karachalios"]
12
+ s.date = %q{2011-02-15}
13
+ s.description = %q{LittleMathPet understands simple math expressions in string format with mutliple variables and returns the result of the expression}
14
+ s.email = %q{kostas.karachalios@me.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rvmrc",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "lib/little_math_pet.rb",
29
+ "little_math_pet.gemspec",
30
+ "spec/little_math_pet_spec.rb",
31
+ "spec/spec_helper.rb"
32
+ ]
33
+ s.homepage = %q{http://github.com/vrinek/little-math-pet}
34
+ s.licenses = ["MIT"]
35
+ s.require_paths = ["lib"]
36
+ s.rubygems_version = %q{1.5.2}
37
+ s.summary = %q{Parses math expressions and returns the result}
38
+ s.test_files = [
39
+ "spec/little_math_pet_spec.rb",
40
+ "spec/spec_helper.rb"
41
+ ]
42
+
43
+ if s.respond_to? :specification_version then
44
+ s.specification_version = 3
45
+
46
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
47
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
48
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
49
+ s.add_development_dependency(%q<rspec>, ["~> 2.5.0"])
50
+ else
51
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
52
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
53
+ s.add_dependency(%q<rspec>, ["~> 2.5.0"])
54
+ end
55
+ else
56
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
57
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
58
+ s.add_dependency(%q<rspec>, ["~> 2.5.0"])
59
+ end
60
+ end
61
+
@@ -0,0 +1,157 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe LittleMathPet do
4
+ context "when a single number is given" do
5
+ equations = {
6
+ "8" => 8.0,
7
+ "78.65" => 78.65,
8
+ "-3.5" => -3.5
9
+ }
10
+
11
+ equations.each do |equation, result|
12
+ it "returns that number in float (#{equation} = #{result})" do
13
+ LittleMathPet.new(equation).calc.should == result
14
+ end
15
+ end
16
+ end
17
+
18
+ context "when a simple equation is given" do
19
+ equations = {
20
+ "5+3" => 8.0,
21
+ "7-5" => 2.0,
22
+ "5-7" => -2.0,
23
+ "5*3" => 15.0,
24
+ "15/5" => 3.0,
25
+ "-15/5" => -3.0,
26
+ "2^3" => 8.0
27
+ }
28
+
29
+ equations.each do |equation, result|
30
+ it "solves the equation (#{equation} = #{result})" do
31
+ LittleMathPet.new(equation).calc.should == result
32
+ end
33
+ end
34
+ end
35
+
36
+ context "when a more complex equation is given" do
37
+ equations = {
38
+ "5+3+10" => 18.0,
39
+ "7-5-2" => 0.0,
40
+ "5-7+6" => 4.0,
41
+ "5*3/10" => 1.5,
42
+ "15/5*2" => 6.0,
43
+ "-15/5*7" => -21.0
44
+ }
45
+
46
+ equations.each do |equation, result|
47
+ it "solves the equation (#{equation} = #{result})" do
48
+ LittleMathPet.new(equation).calc.should == result
49
+ end
50
+ end
51
+
52
+ equations = {
53
+ "5*3+10" => 25.0,
54
+ "10+3*5" => 25.0,
55
+ "5-7/2" => 1.5,
56
+ "-8/2^2" => -2.0,
57
+ "(5+2)*2" => 14.0
58
+ }
59
+
60
+ equations.each do |equation, result|
61
+ it "respects the proper math order (#{equation} = #{result})" do
62
+ LittleMathPet.new(equation).calc.should == equations[equation]
63
+ end
64
+ end
65
+ end
66
+
67
+ context "when a different grammar is used for the equation" do
68
+ equations = {
69
+ "5*3:10" => 1.5,
70
+ "-8/2**2" => -2.0,
71
+ "5 + 7" => 12.0,
72
+ "[5+2] : 2" => 3.5
73
+ }
74
+
75
+ equations.each do |equation, result|
76
+ it "solves the equation (#{equation} = #{result})" do
77
+ LittleMathPet.new(equation).calc.should == result
78
+ end
79
+ end
80
+ end
81
+
82
+ context "when something unkown is given as math" do
83
+ equations = [
84
+ "five * 5",
85
+ "something else",
86
+ "+*+"
87
+ ]
88
+
89
+ equations.each do |equation|
90
+ it "raises an exception (#{equation.inspect})" do
91
+ begin
92
+ LittleMathPet.new(equation).calc
93
+ true.should == false
94
+ rescue => e
95
+ e.message.should == 'Invalid math expression'
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ context "when a variable is given (x => 3)" do
102
+ value = '3'
103
+ equations = {
104
+ "5+x+10" => 18.0,
105
+ "7-5-x" => -1.0,
106
+ "5*x/10" => 1.5,
107
+ "15/5*x" => 9.0,
108
+ "10+x*5" => 25.0,
109
+ "x-7/2" => -0.5,
110
+ "-9/x^2" => -1.0,
111
+ "x*(2+3)/2" => 7.5
112
+ }
113
+
114
+ equations.each do |equation, result|
115
+ it "uses it in place of x (#{equation} = #{result})" do
116
+ LittleMathPet.new(equation).calc(:x => value).should == result
117
+ end
118
+ end
119
+ end
120
+
121
+ context "when multiple variables are given (a => 2, b => 5)" do
122
+ values = {:a => 2, :b => 5}
123
+ equations = {
124
+ "5+a+10/b" => 9.0,
125
+ "7-5-a*b" => -8.0,
126
+ "5^a/10/b" => 0.5,
127
+ "b*(a+3)/2" => 12.5
128
+ }
129
+
130
+ equations.each do |equation, result|
131
+ it "uses them in place of the variables (#{equation} = #{result})" do
132
+ LittleMathPet.new(equation).calc(values).should == result
133
+ end
134
+ end
135
+ end
136
+
137
+ context "when some variables are missing" do
138
+ values = {:a => 2, :b => 5}
139
+ equations = [
140
+ "5+a+10/x",
141
+ "7-5-a*y",
142
+ "c^a/10/b",
143
+ "v*(e+3)/2"
144
+ ]
145
+
146
+ equations.each do |equation, result|
147
+ it "raises an exception (#{equation.inspect})" do
148
+ begin
149
+ LittleMathPet.new(equation).calc.should == result
150
+ true.should == false
151
+ rescue => e
152
+ e.message.should == 'Invalid math expression'
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'the-perfect-gem'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: little_math_pet
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.2
6
+ platform: ruby
7
+ authors:
8
+ - Kostas Karachalios
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-02-15 00:00:00 +02:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: bundler
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 1.0.0
25
+ type: :development
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: jeweler
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: 1.5.2
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: rspec
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 2.5.0
47
+ type: :development
48
+ version_requirements: *id003
49
+ description: LittleMathPet understands simple math expressions in string format with mutliple variables and returns the result of the expression
50
+ email: kostas.karachalios@me.com
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files:
56
+ - LICENSE.txt
57
+ - README.rdoc
58
+ files:
59
+ - .document
60
+ - .rvmrc
61
+ - Gemfile
62
+ - Gemfile.lock
63
+ - LICENSE.txt
64
+ - README.rdoc
65
+ - Rakefile
66
+ - VERSION
67
+ - lib/little_math_pet.rb
68
+ - little_math_pet.gemspec
69
+ - spec/little_math_pet_spec.rb
70
+ - spec/spec_helper.rb
71
+ has_rdoc: true
72
+ homepage: http://github.com/vrinek/little-math-pet
73
+ licenses:
74
+ - MIT
75
+ post_install_message:
76
+ rdoc_options: []
77
+
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: "0"
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: "0"
92
+ requirements: []
93
+
94
+ rubyforge_project:
95
+ rubygems_version: 1.5.2
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: Parses math expressions and returns the result
99
+ test_files:
100
+ - spec/little_math_pet_spec.rb
101
+ - spec/spec_helper.rb