claus 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.
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: []