lambda_gem 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in lambda_gem.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 angelos
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # LambdaGem
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'lambda_gem'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install lambda_gem
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,7 @@
1
+
2
+ bitbucket remote:
3
+
4
+ bitbucket_lambda_gem
5
+
6
+
7
+ git remote add bitbucket_lambda_gem https://akxs14@bitbucket.org/akxs14/lambda-gem.git
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "lambda_gem"
8
+ gem.version = LambdaGem::VERSION
9
+ gem.authors = ["angelos"]
10
+ gem.email = ["angelos.kapsimanis@gmail.com"]
11
+ gem.description = "Lambda expressions support"
12
+ gem.summary = "The current gem provides a lambda
13
+ calculus implementation with the possibility
14
+ to define any arbitrary operator with any
15
+ functionality"
16
+ gem.homepage = ""
17
+
18
+ gem.files = `git ls-files`.split($/)
19
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
20
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
21
+ gem.require_paths = ["lib"]
22
+
23
+ gem.add_development_dependency "rspec", "~> 2.6"
24
+ end
@@ -0,0 +1,59 @@
1
+ # Description:
2
+ # A dictionary structure containing the functionality
3
+ # of the available operators.
4
+ module LambdaGem
5
+
6
+ class Dictionary
7
+ attr_reader :operator_priority
8
+
9
+ def initialize dict=nil
10
+ if dict.nil?
11
+ @operator_dict, @operator_priority = Hash.new, Hash.new
12
+ @operator_priority.default(-1)
13
+ populate_default_dict
14
+ populate_default_priorities
15
+ else
16
+ @operator_dict = dict
17
+ end
18
+ end
19
+
20
+ def count
21
+ @operator_dict.count
22
+ end
23
+
24
+ def [] operator
25
+ @operator_dict[operator]
26
+ end
27
+
28
+ def contains? operator
29
+ @operator_dict.include? operator
30
+ end
31
+
32
+ def add_operator symbol, block, priority
33
+ @operator_dict[symbol] = block
34
+ @operator_priority[symbol] = priority
35
+ end
36
+
37
+ private
38
+ def populate_default_dict
39
+ @operator_dict["="] = lambda { |a, b| a = b }
40
+ @operator_dict["and"] = lambda { |a,b| a and b }
41
+ @operator_dict["or"] = lambda { |a,b| a or b }
42
+ @operator_dict["+"] = lambda { |a,b| a + b }
43
+ @operator_dict["-"] = lambda { |a,b| a - b }
44
+ @operator_dict["*"] = lambda { |a,b| a * b }
45
+ @operator_dict["/"] = lambda { |a,b| a / b }
46
+ end
47
+
48
+ def populate_default_priorities
49
+ @operator_priority["and"] = 1
50
+ @operator_priority["or"] = 1
51
+ @operator_priority["+"] = 1
52
+ @operator_priority["-"] = 1
53
+ @operator_priority["*"] = 2
54
+ @operator_priority["/"] = 2
55
+ @operator_priority["="] = 3
56
+ end
57
+ end
58
+
59
+ end
@@ -0,0 +1,93 @@
1
+ require_relative 'tree'
2
+ require_relative 'dictionary'
3
+
4
+ module LambdaGem
5
+ class Expression
6
+ attr_accessor :tree, :current_order, :dictionary
7
+
8
+ def initialize expression=nil, order=:infix, dictionary=nil
9
+ order = :infix if !@@AVAILABLE_ORDERING.include? order
10
+ @dictionary = Dictionary.new
11
+ @formula, @current_order, @tree = expression, order, Tree.new
12
+ tree_from_expression(expression,order) if !expression.nil?
13
+ end
14
+
15
+ def formula
16
+ @formula
17
+ end
18
+
19
+ def formula= new_expression
20
+ tree_from_expression new_expression
21
+ @formula = new_expression
22
+ end
23
+
24
+ def tree_from_expression expression=@formula, order=:infix
25
+ tokens = tokenize expression
26
+ operator_stack, node_stack = [], []
27
+
28
+ tokens.each do |token|
29
+ token = token.downcase
30
+
31
+ if operator?(token)
32
+ until(operator_stack.empty? or
33
+ operator_stack.last.data == "(" or
34
+ @dictionary.operator_priority[operator_stack.last.data] < @dictionary.operator_priority[token])
35
+ pop_connect_push operator_stack, node_stack
36
+ end
37
+ operator_stack.push(Node.new(token))
38
+ elsif token == "("
39
+ operator_stack.push(Node.new(token))
40
+ elsif token == ")"
41
+ while operator_stack.last.data != "("
42
+ pop_connect_push operator_stack, node_stack
43
+ end
44
+ operator_stack.pop #throw '('
45
+ else
46
+ node_stack.push(Node.new(token))
47
+ end
48
+
49
+ end
50
+
51
+ until operator_stack.empty?
52
+ pop_connect_push operator_stack, node_stack
53
+ end
54
+
55
+ @tree.root = node_stack.last
56
+ @tree
57
+ end
58
+
59
+ def operator?(token)
60
+ @dictionary.contains?(token.to_s)
61
+ end
62
+
63
+ def evaluate
64
+ eval(@tree.root)
65
+ end
66
+
67
+ private
68
+ @@AVAILABLE_ORDERING = [:prefix,:infix,:postfix]
69
+
70
+ def eval node
71
+ if !node.leaf? and operator?(node.data)
72
+ @dictionary[node.data].call( eval(node.left), eval(node.right) )
73
+ else
74
+ #if a number, cast from string to numeric, otherwise return it as-is
75
+ (/[0-9]/ =~ node.data) ? node.data.to_f : node.data
76
+ end
77
+ end
78
+
79
+ def tokenize expression
80
+ expression.gsub('(', ' ( ').gsub(')', ' ) ').split(' ')
81
+ end
82
+
83
+ #pops the topmost node, assigns the next two nodes
84
+ #as its left and right branches and is pushed back
85
+ def pop_connect_push operator_stack, node_stack
86
+ temp = operator_stack.pop
87
+ temp.right = node_stack.pop
88
+ temp.left = node_stack.pop
89
+ node_stack.push temp
90
+ end
91
+ end
92
+ end
93
+
@@ -0,0 +1,9 @@
1
+ require 'version'
2
+ require 'dictionary'
3
+ require 'node'
4
+ require 'tree'
5
+ require 'expression'
6
+
7
+ module LambdaGem
8
+ # Your code goes here...
9
+ end
@@ -0,0 +1,38 @@
1
+ # Description
2
+ # A tree structure that contains the expression
3
+ # in an infix notation tree.
4
+ module LambdaGem
5
+
6
+ class Node
7
+ attr_accessor :left, :right, :data
8
+
9
+ def initialize data=nil
10
+ @data, @left, @right = data, nil, nil
11
+ end
12
+
13
+ def leaf?
14
+ @left.nil? and @right.nil?
15
+ end
16
+
17
+ def purge
18
+ @data, @left, @right = nil, nil, nil
19
+ end
20
+
21
+ def traverse order=:infix
22
+ if leaf?
23
+ @data
24
+ else
25
+ left_child, right_child = @left.traverse(order), @right.traverse(order)
26
+
27
+ strs = case order
28
+ when :prefix then [@data, left_child, right_child]
29
+ when :infix then [left_child, @data, right_child]
30
+ when :postfix then [left_child, right_child, @data]
31
+ else []
32
+ end
33
+ "(" + strs.join(" ") + ")"
34
+ end
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,20 @@
1
+ require_relative 'node'
2
+
3
+ module LambdaGem
4
+ class Tree
5
+ attr_accessor :root
6
+
7
+ def initialize root=nil
8
+ @root = Node.new root
9
+ end
10
+
11
+ def preorder_insert new_data
12
+ new_data
13
+ end
14
+
15
+ def traverse order=:infix
16
+ @root.traverse order
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module LambdaGem
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,33 @@
1
+ require 'lambda_gem'
2
+
3
+ include LambdaGem
4
+
5
+ describe Dictionary do
6
+
7
+ it "the default dictionary should contain seven operators" do
8
+ Dictionary.new.count.should eq(7)
9
+ end
10
+
11
+ it "should return nil for an unknown operator" do
12
+ dict = Dictionary.new
13
+ dict["boing"].should be_nil
14
+ end
15
+
16
+ it "an instance should return the correct lambda" do
17
+ dict = Dictionary.new
18
+ a, b, and_lambda = true, false, lambda { |a,b| a and b }
19
+
20
+ result_dict = dict["and"].call(a, b)
21
+ result_local = and_lambda.call(a, b)
22
+ result_local.should eq(result_dict)
23
+ end
24
+
25
+ it "should use the user defined dictionary if given in initialization" do
26
+ userDict = Hash.new
27
+ userDict["xy"] = lambda { |a,b| a**b }
28
+
29
+ dict = Dictionary.new(userDict)
30
+ dict["xy"].call(2,3).should eq(8)
31
+ end
32
+
33
+ end
@@ -0,0 +1,69 @@
1
+ require 'lambda_gem'
2
+
3
+ include LambdaGem
4
+
5
+ describe Expression do
6
+ it "should have a nil expression if nothing is given" do
7
+ Expression.new().formula.should be_nil
8
+ end
9
+
10
+ it "should have an infix order as default" do
11
+ Expression.new().current_order.should eq(:infix)
12
+ end
13
+
14
+ it "should have infix ordering in case a non-acceotable ordering was passed" do
15
+ Expression.new(nil,:noorder).current_order.should eq(:infix)
16
+ end
17
+
18
+ it "should contain a Tree class instance in @tree" do
19
+ Expression.new().tree.class.should eq(Tree)
20
+ end
21
+
22
+ it "should verify correctly if a node's data are an operator contained in a given dictionary" do
23
+ expression = Expression.new
24
+ expression.operator?('+').should be_true
25
+ end
26
+
27
+ it "should not recognize a number as an operator" do
28
+ expression = Expression.new
29
+ expression.operator?('3').should be_false
30
+ end
31
+
32
+ it "should be able to verify operators from a node" do
33
+ expression, node = Expression.new, Node.new(1)
34
+ expression.operator?(node).should be_false
35
+ end
36
+
37
+ it "should be able to store the expression as a expression tree and traverse it back to its original form" do
38
+ #the expression could also be given as
39
+ # => (nd_age = 1 or nd_age = 2) and nd_gnd = 2
40
+ # it would be parsed correctly
41
+ # but the returned expression couldn't match because of expressions
42
+ expression_test = "(((nd_age = 1) or (nd_age = 2)) and (nd_gnd = 2))"
43
+ expression = Expression.new expression_test, :infix
44
+ expression.tree.traverse(:infix).should eq(expression_test)
45
+ end
46
+
47
+ it "should identify correctly an operator " do
48
+ Expression.new.operator?('+').should be_true
49
+ end
50
+
51
+ it "should not identify a symbol as an operator " do
52
+ Expression.new.operator?('ni_auto').should be_false
53
+ end
54
+
55
+ it "should not identify a digit as an operator " do
56
+ Expression.new.operator?('9').should be_false
57
+ end
58
+
59
+ it "should be able to correctly return all the token orders of an expression" do
60
+ expr_inorder = "(1 + 1)"
61
+ expr_preorder = "(+ 1 1)"
62
+ expr_postorder = "(1 1 +)"
63
+ expr = Expression.new "(1 + 1)"
64
+
65
+ expr.tree.traverse(:prefix).should eq(expr_preorder) and
66
+ expr.tree.traverse(:postfix).should eq(expr_postorder) and
67
+ expr.tree.traverse(:infix).should eq(expr_inorder)
68
+ end
69
+ end
@@ -0,0 +1,15 @@
1
+ require 'lambda_gem'
2
+
3
+ include LambdaGem
4
+
5
+ describe Node do
6
+ it "an empty node is a leaf" do
7
+ Node.new.leaf?
8
+ end
9
+
10
+ it "purge is called, all data in the node must be cleared" do
11
+ node = Node.new(1)
12
+ node.purge
13
+ node.data.should be_nil and node.left.should be_nil and node.right.should be_nil
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ require 'lambda_gem'
2
+
3
+ include LambdaGem
4
+
5
+ describe Tree do
6
+ it "the root should a node with nill value an empty tree" do
7
+ Tree.new.root.data.should be_nil and Tree.new.root.class.should eq(Node)
8
+ end
9
+
10
+ it "the root should be of a node class" do
11
+ Tree.new(1).root.class.should eq(Node)
12
+ end
13
+
14
+ it "every node should contain the data given to it" do
15
+ tree = Tree.new(1)
16
+ tree.root.data.should eq(1)
17
+ end
18
+ end
data/test.rb ADDED
@@ -0,0 +1,24 @@
1
+ require_relative 'lib/tree'
2
+ require_relative 'lib/expression'
3
+
4
+ include LambdaGem
5
+
6
+ tree = Tree.new '+'
7
+ tree.root.left = Node.new(1)
8
+ tree.root.right = Node.new(1)
9
+
10
+ # puts "root #{tree.root.data}"
11
+ # puts "left: #{tree.root.left.data}"
12
+ # puts "right: #{tree.root.right.data}"
13
+
14
+ exp = Expression.new
15
+
16
+ exp.formula = "((nd_gnd = 1) AND
17
+ (nd_agr = 1 OR nd_agr = 2 OR nd_agr = 3 OR nd_agr = 4)) AND
18
+ ((ni_care = 1 OR ni_care = 2 OR ni_care = 3 OR ni_care = 4) AND
19
+ (ni_perf = 1 OR ni_perf = 2 OR ni_perf = 3 OR ni_perf = 4)) AND
20
+ ((na_book = 1 OR na_book = 2))"
21
+ puts exp.tree.traverse :infix
22
+
23
+ exp.formula = "(nd_agr = 1 or nd_agr = 0) and ni_auto = 9"
24
+ puts exp.evaluate
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lambda_gem
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - angelos
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.6'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '2.6'
30
+ description: Lambda expressions support
31
+ email:
32
+ - angelos.kapsimanis@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - LICENSE.txt
40
+ - README.md
41
+ - Rakefile
42
+ - git_settings.txt
43
+ - lambda_gem.gemspec
44
+ - lib/dictionary.rb
45
+ - lib/expression.rb
46
+ - lib/lambda_gem.rb
47
+ - lib/node.rb
48
+ - lib/tree.rb
49
+ - lib/version.rb
50
+ - spec/dictionary_spec.rb
51
+ - spec/expression_spec.rb
52
+ - spec/node_spec.rb
53
+ - spec/tree_spec.rb
54
+ - test.rb
55
+ homepage: ''
56
+ licenses: []
57
+ post_install_message:
58
+ rdoc_options: []
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubyforge_project:
75
+ rubygems_version: 1.8.25
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: The current gem provides a lambda calculus implementation with the possibility
79
+ to define any arbitrary operator with any functionality
80
+ test_files:
81
+ - spec/dictionary_spec.rb
82
+ - spec/expression_spec.rb
83
+ - spec/node_spec.rb
84
+ - spec/tree_spec.rb