heuristics 1.0.1 → 1.0.2
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/README.md +15 -3
- data/lib/heuristics.rb +2 -2
- data/lib/heuristics/tester.rb +22 -1
- data/lib/heuristics/version.rb +1 -1
- data/test/lib/heuristics/functional_test.rb +24 -32
- metadata +2 -2
data/README.md
CHANGED
@@ -41,6 +41,9 @@ Or install it yourself as:
|
|
41
41
|
|
42
42
|
## Usage
|
43
43
|
|
44
|
+
**NOTE**: Order matters. First assumption to return true for all conditions will be used.
|
45
|
+
This means you should write your assumptions in the order from most specific to least specfic.
|
46
|
+
|
44
47
|
# Creates a new heuristic named :field_tester
|
45
48
|
Heuristics.define(:field_tester) do
|
46
49
|
|
@@ -67,10 +70,19 @@ Or install it yourself as:
|
|
67
70
|
# Returns :hash_with_values in this case
|
68
71
|
Heuristics.test(:field_tester, {a: 1})
|
69
72
|
|
73
|
+
**Test an array of value** (Also shows of using heuristic without a name):
|
74
|
+
Heuristics.define do
|
75
|
+
|
76
|
+
# Default value to return if no assumptions match
|
77
|
+
assume_default :set
|
78
|
+
|
79
|
+
assume(:date) { condition { Chronic.parse(value) != nil } }
|
80
|
+
assume(:string) { condition { value.instance_of? String } } }
|
81
|
+
assume(:integer) { condition { value.instance_of? Fixnum } }}
|
82
|
+
end
|
70
83
|
|
71
|
-
|
72
|
-
|
73
|
-
This means you should write your assumptions in the order from most specific to least specfic.
|
84
|
+
Heuristics.test([1,2,3,'23.09.85','1','2','3','4']) # returns :string
|
85
|
+
|
74
86
|
|
75
87
|
## Contributing
|
76
88
|
|
data/lib/heuristics.rb
CHANGED
@@ -8,12 +8,12 @@ module Heuristics
|
|
8
8
|
class << self
|
9
9
|
@@testers = {}
|
10
10
|
|
11
|
-
def define(name, &block)
|
11
|
+
def define(name = :default, &block)
|
12
12
|
raise "A heuristic with the name '#{name}' already exists" unless @@testers[name].nil?
|
13
13
|
@@testers[name] = Tester.new(Docile.dsl_eval(Builder.new, &block))
|
14
14
|
end
|
15
15
|
|
16
|
-
def test(
|
16
|
+
def test(value, name = :default)
|
17
17
|
unless @@testers.key? name
|
18
18
|
raise "Heuristic named #{name} hasn't been defined."
|
19
19
|
else
|
data/lib/heuristics/tester.rb
CHANGED
@@ -5,7 +5,28 @@ module Heuristics
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def test(value)
|
8
|
-
|
8
|
+
freq = Frequency.new
|
9
|
+
[*value].map do |v|
|
10
|
+
freq.add(@builder.tests.map{|k, e| e.check(v) ? k : nil }.reject(&:nil?).first || @builder.default)
|
11
|
+
end
|
12
|
+
|
13
|
+
freq.list.keys.first
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
class Frequency
|
18
|
+
def initialize()
|
19
|
+
@storage = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def add(name)
|
23
|
+
@storage[name] ||= 0
|
24
|
+
@storage[name] += 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def list
|
28
|
+
Hash[@storage.sort_by{|key, value| value }.reverse]
|
29
|
+
end
|
9
30
|
end
|
10
31
|
end
|
11
32
|
end
|
data/lib/heuristics/version.rb
CHANGED
@@ -1,36 +1,15 @@
|
|
1
1
|
require_relative '../../test_helper'
|
2
2
|
|
3
3
|
describe Heuristics do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
# assume_default :string
|
8
|
-
#
|
9
|
-
# assume :integer do
|
10
|
-
# condition { value =~ /\A\d+\Z/ }
|
11
|
-
# end
|
12
|
-
#
|
13
|
-
# assume :email do
|
14
|
-
# condition { value =~ /\A.*@.*\Z/}
|
15
|
-
# end
|
16
|
-
#
|
17
|
-
# assume :date_of_birth do
|
18
|
-
# require 'chronic'
|
19
|
-
#
|
20
|
-
# condition { Chronic.parse(value) }
|
21
|
-
# end
|
22
|
-
#
|
23
|
-
# assume :phone_number do
|
24
|
-
# condition { value.starts_with? '+353' } and
|
25
|
-
# condition { value.scan(/\d/).length > 5 }
|
26
|
-
# end
|
27
|
-
# end
|
4
|
+
it 'should allow skipping the heuristics name' do
|
5
|
+
Heuristics.define { assume_default :string; assume(:email) { condition { false } } }
|
6
|
+
Heuristics.test(1).must_equal :string
|
28
7
|
end
|
29
8
|
|
30
9
|
it 'should allow to use external libs for testing' do
|
31
10
|
require 'chronic'
|
32
11
|
Heuristics.define(:external_lib_test) { assume(:date) { condition { Chronic.parse(value) != nil } } }
|
33
|
-
Heuristics.test(
|
12
|
+
Heuristics.test('23.09.85', :external_lib_test).must_equal :date
|
34
13
|
end
|
35
14
|
|
36
15
|
it 'should return the assumption that first matched all conditions' do
|
@@ -43,19 +22,19 @@ describe Heuristics do
|
|
43
22
|
assume(:string) { condition { value.instance_of? String } }
|
44
23
|
end
|
45
24
|
|
46
|
-
Heuristics.test(
|
47
|
-
Heuristics.test(
|
48
|
-
Heuristics.test(
|
25
|
+
Heuristics.test('23.09.85', :first_come_first_serve).must_equal :date
|
26
|
+
Heuristics.test('27', :first_come_first_serve).must_equal :integer_string
|
27
|
+
Heuristics.test('This is string', :first_come_first_serve).must_equal :string
|
49
28
|
end
|
50
29
|
|
51
30
|
it 'should return default if no assumptions are true' do
|
52
31
|
Heuristics.define(:default_test) { assume_default :string; assume(:email) { condition { false } } }
|
53
|
-
Heuristics.test(:default_test
|
32
|
+
Heuristics.test(1, :default_test).must_equal :string
|
54
33
|
end
|
55
34
|
|
56
35
|
it 'should return nil if no default is set' do
|
57
36
|
Heuristics.define(:default_test2) { assume(:nothing) { condition { false } } }
|
58
|
-
Heuristics.test(:default_test2
|
37
|
+
Heuristics.test(1, :default_test2).must_be :nil?
|
59
38
|
end
|
60
39
|
|
61
40
|
it 'should return the first true assumption' do
|
@@ -64,12 +43,25 @@ describe Heuristics do
|
|
64
43
|
assume(:string) { condition { value.instance_of? String } }
|
65
44
|
assume(:hash) { condition { value.instance_of? String } }
|
66
45
|
end
|
67
|
-
Heuristics.test(
|
46
|
+
Heuristics.test('abc', :assumption_test).must_equal :string
|
68
47
|
end
|
69
48
|
|
70
49
|
it 'should support complex types' do
|
71
50
|
Heuristics.define(:complex_test) { assume_default :integer; assume(:test) { condition { value[:hepp] } } }
|
72
|
-
Heuristics.test(:complex_test
|
51
|
+
Heuristics.test(Object.new, :complex_test).must_equal :integer
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should determine the most frequent type of an array' do
|
55
|
+
require 'chronic'
|
56
|
+
|
57
|
+
Heuristics.define(:array_test) do
|
58
|
+
assume(:date) { condition { Chronic.parse(value) } }
|
59
|
+
assume(:string) { condition { value.instance_of? String } }
|
60
|
+
assume(:integer) { condition { value.instance_of? Fixnum } }
|
61
|
+
end
|
62
|
+
|
63
|
+
Heuristics.test([1,2,3,'a','b','c','d'], :array_test).must_equal :string
|
64
|
+
Heuristics.test([1,2,'a','b','c','23.09.85','23.09.85','23.09.85','23.09.85'], :array_test).must_equal :date
|
73
65
|
end
|
74
66
|
|
75
67
|
it 'should raise an exception if trying to create a heuristic with a name that already exists ' do
|
metadata
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
name: heuristics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.0.
|
5
|
+
version: 1.0.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Peter Haza
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
version_requirements: !ruby/object:Gem::Requirement
|