claus 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.md +25 -0
  2. data/lib/claus.rb +89 -0
  3. data/test/helper.rb +2 -0
  4. data/test/test_claus.rb +43 -0
  5. metadata +65 -0
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # Claus
2
+
3
+ Simple rule expression using a combination of Array and Hash.
4
+
5
+ ## Example
6
+
7
+ ```ruby
8
+
9
+ require 'claus'
10
+ claus = Claus.new(foo: 1, bar: 2)
11
+ claus.match(foo: 1, bar: 2) #=> true
12
+ claus.match(foo: 1, bar: 3) #=> false
13
+ claus.match(foo: 1, bar: 2, baz: 3) #=> true
14
+
15
+ claus = Claus.new(foo: 1, bar: 1..2)
16
+ claus.match(foo: 1, bar: 2) #=> true
17
+
18
+ claus = Claus.new([{foo:1}, {bar:2}])
19
+ claus.match?(foo: 1) #=> true
20
+ claus.match?(bar: 2) #=> true
21
+ claus.match?(baz: 3) #=> false
22
+ ```
23
+
24
+ # License
25
+ [Creative Commons Attribution - CC BY](http://creativecommons.org/licenses/by/3.0)
data/lib/claus.rb ADDED
@@ -0,0 +1,89 @@
1
+ # Santa Claus tells ya if you're naughty or nice.
2
+ #
3
+ # @example
4
+ # claus = Claus.new(foo: 1, bar: 2)
5
+ # claus.match(foo: 1, bar: 2) #=> true
6
+ # claus.match(foo: 1, bar: 3) #=> false
7
+ # claus.match(foo: 1, bar: 2, baz: 3) #=> true
8
+ #
9
+ # claus = Claus.new(foo: 1, bar: 1..2)
10
+ # claus.match(foo: 1, bar: 2) #=> true
11
+ #
12
+ # claus = Claus.new([{foo:1}, {bar:2}])
13
+ # claus.match?(foo: 1) #=> true
14
+ # claus.match?(bar: 2) #=> true
15
+ # claus.match?(baz: 3) #=> false
16
+ #
17
+ class Claus
18
+ def initialize expression
19
+ @ast = compile(expression)
20
+ end
21
+
22
+ def match? value
23
+ @ast.match?(value)
24
+ end
25
+
26
+ protected
27
+ def compile expression
28
+ case expression
29
+ when Hash then AST::Hash.new(expression)
30
+ when Array then AST::List.new(expression)
31
+ else raise ArgumentError, "invalid expression at #{expression}"
32
+ end
33
+ end
34
+
35
+ module AST
36
+ class Node
37
+ attr_reader :ast
38
+ def initialize expression
39
+ @ast = compile(expression)
40
+ end
41
+
42
+ def compile expression
43
+ expression
44
+ end
45
+
46
+ def match? value
47
+ ast == value
48
+ end
49
+ end # Node
50
+
51
+ # TODO: refactor case statements
52
+ class Hash < Node
53
+ def compile expression
54
+ expression.each_with_object({}) do |(k, v), h|
55
+ case v
56
+ when ::Hash then h[k] = Hash.new(v)
57
+ when ::Array then h[k] = List.new(v)
58
+ when ::Range then h[k] = List.new(v)
59
+ else h[k] = Node.new(v)
60
+ end
61
+ end
62
+ end
63
+
64
+ def match? value
65
+ ast.each do |k, node|
66
+ return false unless ::Hash === value && node.match?(value[k])
67
+ end
68
+ true
69
+ end
70
+ end # Hash
71
+
72
+ class List < Node
73
+ def compile expression
74
+ expression.map do |v|
75
+ case v
76
+ when ::Hash then Hash.new(v)
77
+ when ::Array then List.new(v)
78
+ when ::Range then List.new(v)
79
+ else Node.new(v)
80
+ end
81
+ end
82
+ end
83
+
84
+ def match? value
85
+ !!ast.find {|node| node.match?(value)}
86
+ end
87
+ end # List
88
+ end # AST
89
+ end # Claus
data/test/helper.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'minitest/autorun'
2
+ require 'claus'
@@ -0,0 +1,43 @@
1
+ require 'helper'
2
+
3
+ describe 'claus' do
4
+ it 'should match simple AND conditions' do
5
+ assert_equal true, Claus.new(foo: 1).match?(foo: 1)
6
+ assert_equal false, Claus.new(foo: 1).match?(foo: 2)
7
+ assert_equal false, Claus.new(foo: 1).match?(bar: 2)
8
+ assert_equal false, Claus.new(foo: 1).match?(2)
9
+ end
10
+
11
+ it 'should match multiple AND conditions' do
12
+ assert_equal true, Claus.new(foo: 1, bar: 2).match?(foo: 1, bar: 2)
13
+ assert_equal false, Claus.new(foo: 1, bar: 2).match?(foo: 1, bar: 3)
14
+ assert_equal false, Claus.new(foo: 1, bar: 2).match?(foo: 1)
15
+ end
16
+
17
+ it 'should match simple OR conditions' do
18
+ assert_equal true, Claus.new([1, 2]).match?(1)
19
+ assert_equal true, Claus.new(foo: [1, 2]).match?(foo: 1)
20
+ assert_equal true, Claus.new(foo: [1, 2]).match?(foo: 2)
21
+ assert_equal true, Claus.new(foo: 1..2).match?(foo: 1)
22
+ assert_equal true, Claus.new(foo: 1..2).match?(foo: 2)
23
+ assert_equal false, Claus.new(foo: [1, 2]).match?(foo: 3)
24
+ end
25
+
26
+ it 'should match composite AND OR clauses' do
27
+ assert_equal true, Claus.new(foo: 1, bar: 1..2).match?(foo: 1, bar: 2)
28
+ assert_equal false, Claus.new(foo: 1, bar: 1..2).match?(foo: 1, bar: 3)
29
+ assert_equal false, Claus.new(foo: 1, bar: 1..2).match?(foo: 1)
30
+ assert_equal true, Claus.new([{foo: 1}, {bar: 1..2}]).match?(foo: 1)
31
+ assert_equal true, Claus.new([{foo: 1}, {bar: 1..2}]).match?(bar: 1)
32
+ assert_equal false, Claus.new([{foo: 1}, {bar: 1..2}]).match?(foo: 2)
33
+ end
34
+
35
+ it 'should match some wickedly nested ones too' do
36
+ claus = Claus.new(foo: 1, bar: [{baz: 2}, {bar: 1..2}])
37
+
38
+ assert_equal true, claus.match?(foo: 1, bar: {baz: 2})
39
+ assert_equal true, claus.match?(foo: 1, bar: {bar: 1})
40
+ assert_equal false, claus.match?(foo: 1, bar: {baz: 3})
41
+ assert_equal false, claus.match?(foo: 1)
42
+ end
43
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: claus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bharanee Rathna
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
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: '0'
30
+ description: simple hash / array based rule matching engine
31
+ email:
32
+ - deepfryed@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - test/helper.rb
38
+ - test/test_claus.rb
39
+ - lib/claus.rb
40
+ - README.md
41
+ homepage: http://github.com/deepfryed/claus
42
+ licenses: []
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 1.8.23
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: simple hash / array based rule expression
65
+ test_files: []