symbolic-math 0.1.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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +51 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/symbolic-math.rb +209 -0
- data/symbolic-math.gemspec +54 -0
- data/test/helper.rb +10 -0
- data/test/test_symbolic.rb +39 -0
- metadata +75 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Javier Goizueta
|
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,51 @@
|
|
1
|
+
= symbolic
|
2
|
+
|
3
|
+
This is a proof-of-concept experiment to handle symbolic expressions in Ruby, inspired by Sage.
|
4
|
+
|
5
|
+
Symbolic expressions can be built with Ruby syntax in a +symbolic+ block, by declaring variables with +var+:
|
6
|
+
|
7
|
+
symbolic do
|
8
|
+
var :x
|
9
|
+
expr = 2+x # now expr contains a symbolic expression
|
10
|
+
puts expr # -> (2 + x)
|
11
|
+
puts eval(expr) # -> (2 + x)
|
12
|
+
self.x = 1.5
|
13
|
+
puts eval(expr) # -> 3.5
|
14
|
+
puts eval(expr/7) # -> 0.5
|
15
|
+
var :y
|
16
|
+
poly = 3*x**3 - x**2 - y*x + 7
|
17
|
+
puts eval(poly) # -> ((7.875 - (y * 1.5)) + 7)
|
18
|
+
puts eval(poly, :y=>5.0) # -> 7.375
|
19
|
+
end
|
20
|
+
|
21
|
+
Functions can be defined with +fun+:
|
22
|
+
|
23
|
+
symbolic do
|
24
|
+
fun(:sqr){|x| x*x}
|
25
|
+
var :x
|
26
|
+
expr = sqr(sin(x))
|
27
|
+
puts expr # -> sqr(sin(x))
|
28
|
+
self.x = 1.5
|
29
|
+
puts eval(expr) # -> 0.994996248300223
|
30
|
+
end
|
31
|
+
|
32
|
+
== Similar project
|
33
|
+
|
34
|
+
http://github.com/brainopia/symbolic is a similar, more complete project. Because of this the gem released
|
35
|
+
by this project has been renamed to symbolic-math. Note that this project's pretensions are more limited than
|
36
|
+
brainopia's; I only intend to play with syntax to do symbolic Math in Ruby, not to implement any relevant
|
37
|
+
symbolic math functionality.
|
38
|
+
|
39
|
+
== Note on Patches/Pull Requests
|
40
|
+
|
41
|
+
* Fork the project.
|
42
|
+
* Make your feature addition or bug fix.
|
43
|
+
* Add tests for it. This is important so I don't break it in a
|
44
|
+
future version unintentionally.
|
45
|
+
* Commit, do not mess with rakefile, version, or history.
|
46
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
47
|
+
* Send me a pull request. Bonus points for topic branches.
|
48
|
+
|
49
|
+
== Copyright
|
50
|
+
|
51
|
+
Copyright (c) 2009 Javier Goizueta. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "symbolic-math"
|
8
|
+
gem.summary = %Q{Symbolic math expression in Ruby}
|
9
|
+
gem.description = %Q{This is a proof-of-concept experiment inspired by Sage}
|
10
|
+
gem.email = "jgoizueta@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/jgoizueta/symbolic"
|
12
|
+
gem.authors = ["Javier Goizueta"]
|
13
|
+
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
Rake::TestTask.new(:test) do |test|
|
23
|
+
test.libs << 'lib' << 'test'
|
24
|
+
test.pattern = 'test/**/test_*.rb'
|
25
|
+
test.verbose = true
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'rcov/rcovtask'
|
30
|
+
Rcov::RcovTask.new do |test|
|
31
|
+
test.libs << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
task :rcov do
|
37
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
task :test => :check_dependencies
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "symbolic #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,209 @@
|
|
1
|
+
# Proof-of-concept: symbolic expressions in Ruby (inspired by Sage)
|
2
|
+
|
3
|
+
class Symbolic
|
4
|
+
|
5
|
+
INFIX_OPERATORS = {
|
6
|
+
:+ => lambda{|x,y| x+y},
|
7
|
+
:- => lambda{|x,y| x-y},
|
8
|
+
:* => lambda{|x,y| x*y},
|
9
|
+
:/ => lambda{|x,y| x/y},
|
10
|
+
:^ => lambda{|x,y| x**y}, # nice, but wrong precedence!
|
11
|
+
:** => lambda{|x,y| x**y}
|
12
|
+
}
|
13
|
+
|
14
|
+
PREFIX_OPERATORS = {
|
15
|
+
:+ => lambda{|x| +x},
|
16
|
+
:- => lambda{|x| -x}
|
17
|
+
}
|
18
|
+
|
19
|
+
FUNCTIONS = {
|
20
|
+
:sin=>lambda{|x| Math.sin(x)},
|
21
|
+
:cos=>lambda{|x| Math.cos(x)},
|
22
|
+
:tan=>lambda{|x| Math.tan(x)},
|
23
|
+
:asin=>lambda{|x| Math.asin(x)},
|
24
|
+
:acos=>lambda{|x| Math.acos(x)},
|
25
|
+
:atan=>lambda{|x| Math.atan(x)},
|
26
|
+
:atan2=>lambda{|y,x| Math.atan2(y,x)},
|
27
|
+
:sqrt=>lambda{|x| Math.sqrt(x)},
|
28
|
+
:abs=>lambda{|x| x.abs}
|
29
|
+
}
|
30
|
+
|
31
|
+
class Expression
|
32
|
+
|
33
|
+
def initialize(*tree)
|
34
|
+
@tree = tree
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :tree
|
38
|
+
|
39
|
+
INFIX_OPERATORS.each_key do |operator|
|
40
|
+
define_method operator do |other|
|
41
|
+
other = Expression.new(other) unless other.is_a?(Expression)
|
42
|
+
#Expression.new(operator, self.tree, other.tree)
|
43
|
+
Expression.new(operator, self, other)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
PREFIX_OPERATORS.each_key do |operator|
|
48
|
+
define_method :"#{operator}@" do
|
49
|
+
Expression.new(operator, self)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def vars
|
54
|
+
vars = []
|
55
|
+
if @tree.size==1
|
56
|
+
if @tree.first.is_a?(Symbol)
|
57
|
+
unless f=FUNCTIONS[@tree.first] && f.arity==0
|
58
|
+
vars << @tree.first if @tree.first.is_a?(Symbol)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
# TODO: allow an Expression here?
|
62
|
+
else
|
63
|
+
@tree[1..-1].each do |subexpr|
|
64
|
+
case subexpr
|
65
|
+
when Expression
|
66
|
+
vars += subexpr.vars
|
67
|
+
when Symbol
|
68
|
+
vars << subexpr
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
vars.uniq
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_s
|
76
|
+
arity = tree.size - 1
|
77
|
+
case tree.first
|
78
|
+
when Symbol
|
79
|
+
if arity==2 && INFIX_OPERATORS.has_key?(tree.first)
|
80
|
+
"(#{tree[1].to_s} #{tree.first} #{tree[2].to_s})"
|
81
|
+
elsif arity==1 && PREFIX_OPERATORS.has_key?(tree.first)
|
82
|
+
"(#{tree.first} #{tree[1].to_s})"
|
83
|
+
elsif (f = FUNCTIONS[tree.first]) && f.arity==arity
|
84
|
+
"#{tree.first}(#{tree[1..-1].map{|x| x.to_s}.join(',')})"
|
85
|
+
else
|
86
|
+
tree.first
|
87
|
+
end
|
88
|
+
else
|
89
|
+
tree.first
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def eval(values={})
|
94
|
+
arity = tree.size - 1
|
95
|
+
case tree.first
|
96
|
+
when Symbol
|
97
|
+
if arity==2 && op = INFIX_OPERATORS[tree.first]
|
98
|
+
op[Expression.eval(tree[1],values), Expression.eval(tree[2],values)]
|
99
|
+
elsif arity==1 && op = PREFIX_OPERATORS[tree.first]
|
100
|
+
op[Expression.eval(tree[1],values)]
|
101
|
+
elsif (f = FUNCTIONS[tree.first]) && f.arity==arity
|
102
|
+
f[*tree[1..-1].map{|x| Expression.eval(x,values)}]
|
103
|
+
else
|
104
|
+
# assume variable
|
105
|
+
values[tree.first] || self
|
106
|
+
end
|
107
|
+
else
|
108
|
+
tree.first
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.eval(item, values)
|
113
|
+
case item
|
114
|
+
when Expression
|
115
|
+
item.eval(values)
|
116
|
+
else
|
117
|
+
item
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def coerce(other)
|
122
|
+
[Expression.new(other), self]
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.fun(name, mthd=nil, &blk)
|
128
|
+
raise ArgumentError,"Invalid function definition" unless (mthd || blk) && (!mthd || !blk)
|
129
|
+
blk ||= mthd
|
130
|
+
name = name.to_sym
|
131
|
+
arity = blk.arity
|
132
|
+
FUNCTIONS[name] = blk # TODO: local functions (per Symbolic object)
|
133
|
+
define_method name do |*args|
|
134
|
+
if arity != args.size
|
135
|
+
raise ArgumentError,"Invalid number of arguments for #{name} (#{args.size} for #{arity})"
|
136
|
+
end
|
137
|
+
Expression.new(name, *args)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
FUNCTIONS.each_pair do |f, mth|
|
142
|
+
Symbolic.fun f, mth
|
143
|
+
end
|
144
|
+
|
145
|
+
def initialize
|
146
|
+
@vars = {}
|
147
|
+
end
|
148
|
+
|
149
|
+
attr_reader :vars
|
150
|
+
|
151
|
+
def var(*names)
|
152
|
+
names.each do |name|
|
153
|
+
name = name.to_sym
|
154
|
+
@vars[name] = nil
|
155
|
+
instance_variable_set "@#{name}", Expression.new(name)
|
156
|
+
self.class.class_eval{
|
157
|
+
attr_reader name
|
158
|
+
# can't decide on assignment syntax:
|
159
|
+
# 1. assignment operator (requires self) self.x = 1.0;
|
160
|
+
define_method :"#{name}=" do |value|
|
161
|
+
assign name, value
|
162
|
+
end
|
163
|
+
# 2. method assign_x 1.0;
|
164
|
+
define_method :"assign_#{name}" do |value|
|
165
|
+
assign name, value
|
166
|
+
end
|
167
|
+
# 3. or use assing :x, 1.0;
|
168
|
+
# More indecision: rename 'assign' to 'set' ? 'let' ?
|
169
|
+
}
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def assign(name, value)
|
174
|
+
@vars[name.to_sym] = value
|
175
|
+
end
|
176
|
+
|
177
|
+
def execute(blk)
|
178
|
+
if blk.arity==1
|
179
|
+
blk.call(self)
|
180
|
+
else
|
181
|
+
self.instance_eval(&blk)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def eval(expr, values={})
|
186
|
+
expr.eval(@vars.merge(values))
|
187
|
+
end
|
188
|
+
|
189
|
+
def fun(name, mthd=nil, &blk)
|
190
|
+
self.class.fun name, mthd, &blk
|
191
|
+
end
|
192
|
+
|
193
|
+
def macro(name, &blk)
|
194
|
+
self.class.class_eval{define_method name, blk}
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
def symbolic(*args, &blk)
|
200
|
+
s = Symbolic.new(*args)
|
201
|
+
s.execute blk
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
# TODO:
|
206
|
+
# consider this: add reference to Symbolic object in Expression;
|
207
|
+
# use it to access local functions defined for a Symbolic (not
|
208
|
+
# globally in FUNCTIONS as now) and to access variables, so
|
209
|
+
# expr.eval can be used instead of eval(expr)
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{symbolic-math}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Javier Goizueta"]
|
12
|
+
s.date = %q{2009-12-10}
|
13
|
+
s.description = %q{This is a proof-of-concept experiment inspired by Sage}
|
14
|
+
s.email = %q{jgoizueta@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/symbolic-math.rb",
|
27
|
+
"symbolic-math.gemspec",
|
28
|
+
"test/helper.rb",
|
29
|
+
"test/test_symbolic.rb"
|
30
|
+
]
|
31
|
+
s.homepage = %q{http://github.com/jgoizueta/symbolic}
|
32
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
s.rubygems_version = %q{1.3.5}
|
35
|
+
s.summary = %q{Symbolic math expression in Ruby}
|
36
|
+
s.test_files = [
|
37
|
+
"test/helper.rb",
|
38
|
+
"test/test_symbolic.rb"
|
39
|
+
]
|
40
|
+
|
41
|
+
if s.respond_to? :specification_version then
|
42
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
43
|
+
s.specification_version = 3
|
44
|
+
|
45
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
46
|
+
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
47
|
+
else
|
48
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
49
|
+
end
|
50
|
+
else
|
51
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestSymbolic < Test::Unit::TestCase
|
4
|
+
|
5
|
+
should "obtain symbolic objects from expressions involving declared variables" do
|
6
|
+
assert_equal Symbolic::Expression, symbolic{var :x; x*3}.class
|
7
|
+
assert_equal Symbolic::Expression, symbolic{var :x; 3*x}.class
|
8
|
+
assert_equal Symbolic::Expression, symbolic{var :x; x+7}.class
|
9
|
+
assert_equal Symbolic::Expression, symbolic{var :x; sin(x)}.class
|
10
|
+
end
|
11
|
+
|
12
|
+
should "evaluate symbolic expressions correctly" do
|
13
|
+
assert_equal 3.0, symbolic{var :x; self.x=1.5; eval(x*2)}
|
14
|
+
assert_equal 3.0, symbolic{var :x; self.x=1.5; eval(2*x)}
|
15
|
+
assert_equal -1.5, symbolic{var :x; self.x=1.5; eval(-x)}
|
16
|
+
assert_in_delta 0.997494986604054, symbolic{var :x; self.x=1.5; eval(sin(x))}, 1E-10
|
17
|
+
assert_in_delta -0.676873339089758, symbolic{var :x; self.x=1.5; eval(2*sin(x**3)-x/7)}, 1E-10
|
18
|
+
end
|
19
|
+
|
20
|
+
should "evaluate symbolic expressions correctly with hash parameters" do
|
21
|
+
assert_equal 3.0, symbolic{var :x; eval(x*2, :x=>1.5)}
|
22
|
+
assert_equal 3.0, symbolic{var :x; eval(2*x, :x=>1.5)}
|
23
|
+
end
|
24
|
+
|
25
|
+
should "evaluate partially expression with free variables" do
|
26
|
+
assert_equal "(4.0 - (2.0 * (y ** 2)))", symbolic{var :x, :y; eval(x*2-x*y**2, :x=>2.0).to_s}
|
27
|
+
end
|
28
|
+
|
29
|
+
should "allow definition of functions" do
|
30
|
+
assert_equal "sqr(7)", symbolic{fun(:sqr){|x| x*x}; sqr(7).to_s}
|
31
|
+
assert_equal 49, symbolic{fun(:sqr){|x| x*x}; eval(sqr(7))}
|
32
|
+
end
|
33
|
+
|
34
|
+
should "detect variables used in expressions" do
|
35
|
+
assert_equal [:x], symbolic{var :x, :y; (sin(x*3.5)+2-x).vars}
|
36
|
+
assert_equal [:x,:y], symbolic{var :x, :y; (sin(x*3.5)+2-y).vars}
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: symbolic-math
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Javier Goizueta
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-10 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: thoughtbot-shoulda
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
description: This is a proof-of-concept experiment inspired by Sage
|
26
|
+
email: jgoizueta@gmail.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- LICENSE
|
33
|
+
- README.rdoc
|
34
|
+
files:
|
35
|
+
- .document
|
36
|
+
- .gitignore
|
37
|
+
- LICENSE
|
38
|
+
- README.rdoc
|
39
|
+
- Rakefile
|
40
|
+
- VERSION
|
41
|
+
- lib/symbolic-math.rb
|
42
|
+
- symbolic-math.gemspec
|
43
|
+
- test/helper.rb
|
44
|
+
- test/test_symbolic.rb
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://github.com/jgoizueta/symbolic
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options:
|
51
|
+
- --charset=UTF-8
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.3.5
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Symbolic math expression in Ruby
|
73
|
+
test_files:
|
74
|
+
- test/helper.rb
|
75
|
+
- test/test_symbolic.rb
|