parsecs 0.2.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ext/libnativemath/extconf.rb +61 -0
- data/lib/parsec.rb +41 -0
- data/lib/string_to_boolean_refinements.rb +10 -0
- data/test/test_parsec.rb +86 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 61b24503f941948f023ee022527c79b418cfe3186dcd769d2a38ab0df630ff37
|
4
|
+
data.tar.gz: 2d7ad237ace66c7b8322b4c39c1e122a073a6a27f04ee55e7a0ccf02da62eef5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 574e305a618c0507f41c44fb79981bb16842e46ddedbaa053119c7fcadd45555c8f157008324a451e3d66a69ce8e09a8b40efa3783b808266f7b116b2323b037
|
7
|
+
data.tar.gz: 9ba3a929a6bfbd8e62434f08226df0eee34c36b1f2386f5f44f4b33f5e25333d689f3b7f43eb1e839a5a2f6060844b158befbcc56faa0f1dae9eb6ccde05ab71
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# ext/extconf.rb
|
2
|
+
require 'mkmf'
|
3
|
+
|
4
|
+
# During gem install step, the path is different
|
5
|
+
BASEDIR = if File.exist?('parsec.gemspec')
|
6
|
+
'.'
|
7
|
+
else
|
8
|
+
'../..'
|
9
|
+
end
|
10
|
+
|
11
|
+
LIBDIR = RbConfig::CONFIG['libdir']
|
12
|
+
INCLUDEDIR = RbConfig::CONFIG['includedir']
|
13
|
+
MUPARSER_HEADERS = "#{BASEDIR}/ext/equations-parser/parser".freeze
|
14
|
+
MUPARSER_LIB = "#{BASEDIR}/ext/equations-parser".freeze
|
15
|
+
|
16
|
+
HEADER_DIRS = [INCLUDEDIR, MUPARSER_HEADERS].freeze
|
17
|
+
|
18
|
+
puts HEADER_DIRS
|
19
|
+
puts LIBDIR
|
20
|
+
|
21
|
+
# setup constant that is equal to that of the file path that holds
|
22
|
+
# that static libraries that will need to be compiled against
|
23
|
+
LIB_DIRS = [LIBDIR, MUPARSER_LIB].freeze
|
24
|
+
|
25
|
+
# array of all libraries that the C extension should be compiled against
|
26
|
+
libs = ['-lmuparserx']
|
27
|
+
|
28
|
+
dir_config('libnativemath', HEADER_DIRS, LIB_DIRS)
|
29
|
+
|
30
|
+
abort 'swig is missing. Please install it.' unless find_executable('cmake')
|
31
|
+
|
32
|
+
abort 'swig is missing. Please install it.' unless find_executable('swig')
|
33
|
+
|
34
|
+
# iterate though the libs array, and append them
|
35
|
+
# to the $LOCAL_LIBS array used for the makefile creation
|
36
|
+
libs.each do |lib|
|
37
|
+
$LOCAL_LIBS << "#{lib} "
|
38
|
+
end
|
39
|
+
|
40
|
+
Dir.chdir(BASEDIR) do
|
41
|
+
system('git submodule update --init --recursive')
|
42
|
+
|
43
|
+
Dir.chdir('ext/equations-parser/') do
|
44
|
+
system('cmake CMakeLists.txt -DCMAKE_BUILD_TYPE=Release')
|
45
|
+
system('make')
|
46
|
+
end
|
47
|
+
|
48
|
+
Dir.chdir('ext/libnativemath/') do
|
49
|
+
system('swig -c++ -ruby libnativemath.i')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
unless File.exist?("#{MUPARSER_HEADERS}/mpParser.h")
|
54
|
+
abort 'mpParser.h header is missing.'
|
55
|
+
end
|
56
|
+
|
57
|
+
unless File.exist?("#{MUPARSER_LIB}/libmuparserx.a")
|
58
|
+
abort 'libmuparserx.a is missing.'
|
59
|
+
end
|
60
|
+
|
61
|
+
create_makefile('ext/libnativemath/libnativemath')
|
data/lib/parsec.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'string_to_boolean_refinements'
|
2
|
+
require 'libnativemath'
|
3
|
+
|
4
|
+
module Parsec
|
5
|
+
# This is the main class responsible to evaluate the equations
|
6
|
+
class Parsec
|
7
|
+
using StringToBooleanRefinements
|
8
|
+
|
9
|
+
VERSION = '0.2.14'.freeze
|
10
|
+
|
11
|
+
def self.eval_equation(equation)
|
12
|
+
# This line removes all spaces that are not between quotation marks
|
13
|
+
# https://stackoverflow.com/questions/205521/using-regex-to-replace-all-spaces-not-in-quotes-in-ruby?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
|
14
|
+
equation.gsub!(/( |(".*?"))/, '\\2')
|
15
|
+
|
16
|
+
convert(Libnativemath.native_eval(equation))
|
17
|
+
end
|
18
|
+
|
19
|
+
private_class_method
|
20
|
+
|
21
|
+
def self.convert(ans)
|
22
|
+
case ans['value']
|
23
|
+
when 'inf' then return 'Infinity'
|
24
|
+
when 'nan' then return ans['value']
|
25
|
+
end
|
26
|
+
|
27
|
+
case ans['type']
|
28
|
+
when 'int' then return ans['value'].to_i
|
29
|
+
when 'float' then return ans['value'].to_f
|
30
|
+
when 'boolean' then return ans['value'].to_bool
|
31
|
+
when 'string' then return verify_string(ans['value'])
|
32
|
+
when 'c' then return 'complex number'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.verify_string(output)
|
37
|
+
raise ArgumentError, output.sub('Error: ', '') if output.include?('Error')
|
38
|
+
output.delete('\"')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# This module add refinements to cast string to boolean
|
2
|
+
module StringToBooleanRefinements
|
3
|
+
refine String do
|
4
|
+
def to_bool
|
5
|
+
return true if self == true || self =~ /(true|t|yes|y|1|on)$/i
|
6
|
+
return false if self == false || nil? || strip.empty? || self =~ /(false|f|no|n|0|off)$/i
|
7
|
+
raise ArgumentError, "invalid value for Boolean: \"#{self}\""
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
data/test/test_parsec.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'parsec'
|
3
|
+
|
4
|
+
# This class test all possible equations for this gem
|
5
|
+
class TestParsec < Minitest::Test
|
6
|
+
def test_defined
|
7
|
+
assert defined?(Parsec::Parsec)
|
8
|
+
assert defined?(Parsec::Parsec::VERSION)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_simple_math_equations
|
12
|
+
parser = Parsec::Parsec
|
13
|
+
assert_equal(10, parser.eval_equation('(5 + 1) + (6 - 2)'))
|
14
|
+
assert_equal(16, parser.eval_equation('4 + 4 * 3'))
|
15
|
+
assert_equal(2, parser.eval_equation('10.5 / 5.25'))
|
16
|
+
assert_equal(5, parser.eval_equation('abs(-5)'))
|
17
|
+
assert_equal(1, parser.eval_equation('log10(10)'))
|
18
|
+
assert_equal(4, parser.eval_equation('round(4.4)'))
|
19
|
+
assert_equal(729, parser.eval_equation('(3^3)^2'))
|
20
|
+
assert_equal(196_83, parser.eval_equation('3^(3^(2))'))
|
21
|
+
assert_equal(362_880_0, parser.eval_equation('10!'))
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_complex_math_equations
|
25
|
+
parser = Parsec::Parsec
|
26
|
+
assert_equal(6, parser.eval_equation('sqrt(16) + cbrt(8)'))
|
27
|
+
assert_equal(4.30259, parser.eval_equation('log10(10) + ln(e) + log(10)'))
|
28
|
+
assert_equal(2.0, parser.eval_equation('sin(1) + cos(0) + tan(0.15722)'))
|
29
|
+
assert_equal(16, parser.eval_equation('max(1, 2) + min(3, 4) + sum(5, 6)'))
|
30
|
+
assert_equal(9.6, parser.eval_equation('avg(9, 9.8, 10)'))
|
31
|
+
assert_equal(8, parser.eval_equation('pow(2, 3)'))
|
32
|
+
assert_equal(4.56, parser.eval_equation('round_decimal(4.559, 2)'))
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_if_then_else_equations
|
36
|
+
parser = Parsec::Parsec
|
37
|
+
assert_equal('bigger', parser.eval_equation('4 > 2 ? "bigger" : "smaller"'))
|
38
|
+
assert_equal(true, parser.eval_equation('2 == 2 ? true : false'))
|
39
|
+
assert_equal(false, parser.eval_equation('2 != 2 ? true : false'))
|
40
|
+
assert_equal('yes', parser.eval_equation('"this" == "this" ? "yes" : "no"'))
|
41
|
+
assert_equal('yes', parser.eval_equation('"this" != "that" ? "yes" : "no"'))
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_logic_manipulation
|
45
|
+
parser = Parsec::Parsec
|
46
|
+
assert_equal(false, parser.eval_equation('true and false'))
|
47
|
+
assert_equal(true, parser.eval_equation('true or false'))
|
48
|
+
assert_equal(false, parser.eval_equation('(3==3) and (3!=3)'))
|
49
|
+
assert_equal(true, parser.eval_equation('exp(1) == e'))
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_simple_string_manipulation
|
53
|
+
parser = Parsec::Parsec
|
54
|
+
assert_equal(11, parser.eval_equation('length("test string")'))
|
55
|
+
assert_equal('TEST STRING', parser.eval_equation('toupper("test string")'))
|
56
|
+
assert_equal('test string', parser.eval_equation('tolower("TEST STRING")'))
|
57
|
+
assert_equal('Hello World', parser.eval_equation('concat("Hello ", "World")'))
|
58
|
+
assert_equal(5, parser.eval_equation('str2number("5")'))
|
59
|
+
assert_equal('Hello', parser.eval_equation('left("Hello World", 5)'))
|
60
|
+
assert_equal('World', parser.eval_equation('right("Hello World", 5)'))
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_complex_string_manipulation
|
64
|
+
parser = Parsec::Parsec
|
65
|
+
assert_equal('HELLO WORLD', parser.eval_equation('toupper(concat("hello ", "world"))'))
|
66
|
+
assert_equal('test lowercase', parser.eval_equation('tolower("TEST LOWERCASE")'))
|
67
|
+
assert_equal('Hello', parser.eval_equation('left("Hello World", 5)'))
|
68
|
+
assert_equal('World', parser.eval_equation('right("Hello World", 5)'))
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_general_equations
|
72
|
+
parsec = Parsec::Parsec
|
73
|
+
assert_equal(1, parsec.eval_equation('((0.09/1.0)+2.58)-1.67'))
|
74
|
+
assert_equal(40.6853, parsec.eval_equation('10^log(3+2)'))
|
75
|
+
assert_equal(1, parsec.eval_equation('log(e)'))
|
76
|
+
assert_equal(2, parsec.eval_equation('2^5^0'))
|
77
|
+
assert_equal('yes', parsec.eval_equation('5 > 3 ? "yes" : "no"'))
|
78
|
+
assert_equal(1, parsec.eval_equation('"this" == "this" ? 1 : 0'))
|
79
|
+
assert_equal(9.9812, parsec.eval_equation('sqrt(9)+cbrt(8)+abs(-4.9812)'))
|
80
|
+
assert_equal(3_628_680, parsec.send(:eval_equation, '10! - 5! * -(-1)'))
|
81
|
+
assert_equal(true, parsec.eval_equation('sum(1,2,3,4,5) == max(14.99, 15)'))
|
82
|
+
assert_equal(0.55, parsec.eval_equation('avg(1,2,3,4,5,6,7,8,9,10) / 10'))
|
83
|
+
assert_equal(5, parsec.eval_equation('round(4.62)'))
|
84
|
+
assert_equal(4.63, parsec.eval_equation('round_decimal(4.625, 2)'))
|
85
|
+
end
|
86
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: parsecs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.14
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nilton Vasques
|
8
|
+
- Victor Cordeiro
|
9
|
+
- Beatriz Fagundes
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2018-05-23 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: minitest
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "~>"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '5.10'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '5.10'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: rake
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '12.1'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '12.1'
|
43
|
+
description: Parsecs
|
44
|
+
email:
|
45
|
+
- nilton.vasques@gmail.com
|
46
|
+
- victorcorcos@gmail.com
|
47
|
+
- beatrizsfslima@gmail.com
|
48
|
+
executables: []
|
49
|
+
extensions:
|
50
|
+
- ext/libnativemath/extconf.rb
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- ext/libnativemath/extconf.rb
|
54
|
+
- lib/parsec.rb
|
55
|
+
- lib/string_to_boolean_refinements.rb
|
56
|
+
- test/test_parsec.rb
|
57
|
+
homepage: https://github.com/niltonvasques/parsec
|
58
|
+
licenses:
|
59
|
+
- mit
|
60
|
+
metadata: {}
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
- ext/libnativemath
|
66
|
+
- "."
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 2.7.6
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: A gem to evaluate math equations using a lighter and faster version of the
|
83
|
+
muparserx C++ library
|
84
|
+
test_files:
|
85
|
+
- test/test_parsec.rb
|