pattern-proc 0.0.3 → 0.0.4
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.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/Gemfile.lock +10 -0
- data/lib/pattern_proc.rb +130 -109
- data/pattern-proc.gemspec +1 -1
- data/spec/lib/object_method_spec.rb +80 -0
- data/spec/lib/pattern_proc_spec.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adc2ed80e8a4406782666406fd1cda3117de27ad
|
4
|
+
data.tar.gz: 14792f45f789de53c59a60cf429d1d8e86151645
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f18e19c8a4ad26628d01f35179f94aad549d9ea350c15fb6880524e0406a15758e1c52de4baf5dfb9379ba766c95761b755b692c8957cac33433e95444667c05
|
7
|
+
data.tar.gz: 4fcdedf9e878868403999bdd127d216d60b4030b90a3a5cb8f4b65f6a1b409de132a3a39b59ec5529f375e4e8d268fbdbdce3dc8e9bd04b477f3468027e400a5
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
GEM
|
2
2
|
remote: https://rubygems.org/
|
3
3
|
specs:
|
4
|
+
coderay (1.1.0)
|
4
5
|
diff-lcs (1.2.5)
|
6
|
+
metaclass (0.0.4)
|
7
|
+
method_source (0.8.2)
|
8
|
+
pry (0.9.12.6)
|
9
|
+
coderay (~> 1.0)
|
10
|
+
method_source (~> 0.8)
|
11
|
+
slop (~> 3.4)
|
5
12
|
rspec (3.0.0)
|
6
13
|
rspec-core (~> 3.0.0)
|
7
14
|
rspec-expectations (~> 3.0.0)
|
@@ -14,9 +21,12 @@ GEM
|
|
14
21
|
rspec-mocks (3.0.2)
|
15
22
|
rspec-support (~> 3.0.0)
|
16
23
|
rspec-support (3.0.2)
|
24
|
+
slop (3.5.0)
|
17
25
|
|
18
26
|
PLATFORMS
|
19
27
|
ruby
|
20
28
|
|
21
29
|
DEPENDENCIES
|
30
|
+
metaclass
|
31
|
+
pry
|
22
32
|
rspec
|
data/lib/pattern_proc.rb
CHANGED
@@ -1,146 +1,167 @@
|
|
1
|
-
|
1
|
+
require 'metaclass'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
module PatternProc
|
4
|
+
def self.included(klass)
|
5
|
+
klass.extend ClassMethods
|
6
|
+
Object.include ObjectMethods
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
case_obj = PatternProcCase.new(args, &block)
|
11
|
-
add_case case_obj
|
12
|
-
case_obj
|
13
|
-
end
|
9
|
+
class PatternProc
|
14
10
|
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
def initialize(cases = [])
|
12
|
+
@arity = -1
|
13
|
+
@cases = []
|
14
|
+
cases.each do |c| add_case c end
|
15
|
+
end
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
elsif @arity != case_obj.arity
|
24
|
-
raise "mismatched arity"
|
17
|
+
def with(*args, &block)
|
18
|
+
case_obj = PatternProcCase.new(args, &block)
|
19
|
+
add_case case_obj
|
20
|
+
case_obj
|
25
21
|
end
|
26
|
-
@cases << case_obj
|
27
|
-
end
|
28
22
|
|
23
|
+
def to_proc
|
24
|
+
->(*args) { call(args) }
|
25
|
+
end
|
29
26
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
raise "no match"
|
27
|
+
private
|
28
|
+
def add_case(case_obj)
|
29
|
+
if @arity == -1
|
30
|
+
@arity = case_obj.arity
|
31
|
+
elsif @arity != case_obj.arity
|
32
|
+
raise "mismatched arity"
|
37
33
|
end
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
@cases << case_obj
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def call(args)
|
39
|
+
if args.size == @arity
|
40
|
+
best_match = find_matches(args, true).first
|
41
|
+
if best_match
|
42
|
+
best_match.to_proc.call(args)
|
43
|
+
else
|
44
|
+
raise "no match"
|
45
|
+
end
|
46
|
+
elsif args.size < @arity
|
47
|
+
sliced_cases = find_matches(args, false)
|
48
|
+
if sliced_cases.size > 0
|
49
|
+
PatternProc.new(sliced_cases).to_proc
|
50
|
+
else
|
51
|
+
raise "no match"
|
52
|
+
end
|
42
53
|
else
|
43
|
-
raise "
|
54
|
+
raise "too many args"
|
44
55
|
end
|
45
|
-
else
|
46
|
-
raise "too many args"
|
47
56
|
end
|
48
|
-
end
|
49
57
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
def find_matches(args, stop_at_first_match)
|
59
|
+
results = []
|
60
|
+
sorted_cases = @cases.sort do |case_obj_1, case_obj_2|
|
61
|
+
case_obj_1.specificity <=> case_obj_2.specificity
|
62
|
+
end.reverse
|
63
|
+
sorted_cases.each do |case_obj|
|
64
|
+
result = case_obj.make_subcase(args)
|
65
|
+
if result
|
66
|
+
results << result
|
67
|
+
if stop_at_first_match
|
68
|
+
break
|
69
|
+
end
|
61
70
|
end
|
62
71
|
end
|
72
|
+
results
|
63
73
|
end
|
64
|
-
results
|
65
74
|
end
|
66
|
-
end
|
67
75
|
|
68
|
-
class PatternProcCase
|
76
|
+
class PatternProcCase
|
69
77
|
|
70
|
-
|
71
|
-
|
78
|
+
attr_reader :proc_applied_level
|
79
|
+
attr_reader :proc_arity
|
72
80
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
81
|
+
def initialize(args, previous_specificity = 0, proc_arity = 0, &block)
|
82
|
+
@expected_args = args
|
83
|
+
@proc = block
|
84
|
+
@proc_arity = proc_arity
|
85
|
+
@previous_specificity = previous_specificity || 0
|
86
|
+
if !block.nil? && block.arity > 0
|
87
|
+
@proc_arity = block.arity
|
88
|
+
end
|
80
89
|
end
|
81
|
-
end
|
82
90
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
91
|
+
def returns(value)
|
92
|
+
@return_value = value
|
93
|
+
self
|
94
|
+
end
|
87
95
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
96
|
+
# private ish
|
97
|
+
def expected_arity
|
98
|
+
@expected_args.size || 0
|
99
|
+
end
|
92
100
|
|
93
|
-
|
94
|
-
|
95
|
-
|
101
|
+
def arity
|
102
|
+
expected_arity + proc_arity
|
103
|
+
end
|
96
104
|
|
97
|
-
|
98
|
-
|
99
|
-
|
105
|
+
def specificity
|
106
|
+
expected_arity + @previous_specificity
|
107
|
+
end
|
100
108
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
109
|
+
def make_subcase(args)
|
110
|
+
match_len = [args.size, @expected_args.size].min
|
111
|
+
expected = @expected_args.take(match_len)
|
112
|
+
actual = args.take(match_len)
|
113
|
+
if expected == actual
|
114
|
+
new_proc = to_proc.curry
|
115
|
+
curry_count = args.size - @expected_args.size
|
116
|
+
new_arity = proc_arity
|
117
|
+
if curry_count > 0
|
118
|
+
send_args = args.drop(match_len).take(curry_count)
|
119
|
+
new_proc = new_proc.call(*send_args)
|
120
|
+
new_arity -= curry_count
|
121
|
+
if new_arity == 0
|
122
|
+
return PatternProcCase.new([], specificity).returns(new_proc)
|
123
|
+
elsif !(new_proc.is_a?(Proc))
|
124
|
+
raise "uh oh"
|
125
|
+
end
|
117
126
|
end
|
127
|
+
PatternProcCase.new(@expected_args.drop(match_len), specificity, new_arity, &new_proc).returns(@return_value)
|
128
|
+
else
|
129
|
+
nil
|
118
130
|
end
|
119
|
-
PatternProcCase.new(@expected_args.drop(match_len), specificity, new_arity, &new_proc).returns(@return_value)
|
120
|
-
else
|
121
|
-
nil
|
122
131
|
end
|
123
|
-
end
|
124
132
|
|
125
|
-
|
126
|
-
|
133
|
+
def to_proc
|
134
|
+
@proc || ->(*args) { @return_value }
|
135
|
+
end
|
127
136
|
end
|
128
|
-
end
|
129
137
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
138
|
+
module ObjectMethods
|
139
|
+
|
140
|
+
def pattern(method)
|
141
|
+
find_or_create_pattern self.__metaclass__, method
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
def find_or_create_pattern(receiver, method)
|
146
|
+
@__pattern ||= {}
|
147
|
+
unless @__pattern[method]
|
148
|
+
proc_obj = PatternProc.new
|
149
|
+
receiver.class_eval do
|
150
|
+
define_method(method) do |*args|
|
151
|
+
curried_method = proc_obj.to_proc.curry
|
152
|
+
curried_method[*args]
|
153
|
+
end
|
140
154
|
end
|
155
|
+
@__pattern[method] = proc_obj
|
141
156
|
end
|
142
|
-
@
|
157
|
+
@__pattern[method]
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
module ClassMethods
|
163
|
+
def pattern(method)
|
164
|
+
find_or_create_pattern self, method
|
143
165
|
end
|
144
|
-
@__partials[method]
|
145
166
|
end
|
146
167
|
end
|
data/pattern-proc.gemspec
CHANGED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'pattern_proc'
|
2
|
+
|
3
|
+
class TestObjectClass
|
4
|
+
include PatternProc
|
5
|
+
def my_func(a,b,c)
|
6
|
+
raise "don't call me"
|
7
|
+
end
|
8
|
+
|
9
|
+
pattern(:p_func).with(3,2).returns(5)
|
10
|
+
pattern(:p_func).with do |x,y| x * y end
|
11
|
+
end
|
12
|
+
|
13
|
+
class TestSingletonClass
|
14
|
+
class << self
|
15
|
+
include PatternProc
|
16
|
+
def class_func(a,b,c)
|
17
|
+
raise "don't call me"
|
18
|
+
end
|
19
|
+
|
20
|
+
pattern(:p_cls_func).with(3) do |y| y * y * y end
|
21
|
+
pattern(:p_cls_func).with do |x, y| x + y end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "pattern object methods" do
|
26
|
+
context "class" do
|
27
|
+
let (:obj) { TestObjectClass.new }
|
28
|
+
context "in declaration" do
|
29
|
+
it "allows declaration of pattern methods in a class" do
|
30
|
+
obj.p_func(3,2).should == 5
|
31
|
+
obj.p_func(3,3).should == 9
|
32
|
+
end
|
33
|
+
end
|
34
|
+
context "after the fact" do
|
35
|
+
it "allows replacing methods on an instance" do
|
36
|
+
obj.pattern(:my_func).with(1,2,3).returns(7)
|
37
|
+
obj.pattern(:my_func).with(2,3,4).returns(9)
|
38
|
+
|
39
|
+
obj.my_func(1,2).(3).should == 7
|
40
|
+
obj.my_func(2).(3,4).should == 9
|
41
|
+
end
|
42
|
+
|
43
|
+
it "allows declaring new methods on an instance" do
|
44
|
+
obj.pattern(:new_func).with(:a, :b).returns(:c)
|
45
|
+
obj.pattern(:new_func).with(:d, :e).returns(:f)
|
46
|
+
|
47
|
+
obj.new_func(:a).(:b).should == :c
|
48
|
+
obj.new_func(:d,:e).should == :f
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "object" do
|
54
|
+
let (:klass) { TestSingletonClass }
|
55
|
+
context "in declaration" do
|
56
|
+
it "allows declaration of pattern class methods in a class" do
|
57
|
+
klass.p_cls_func(3,2).should == 8
|
58
|
+
klass.p_cls_func(9,3).should == 12
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "after the fact" do
|
63
|
+
it "allows replacing methods on a class" do
|
64
|
+
klass.pattern(:class_func).with(1,2,3).returns(7)
|
65
|
+
klass.pattern(:class_func).with(2,3,4).returns(9)
|
66
|
+
|
67
|
+
klass.class_func(1,2).(3).should == 7
|
68
|
+
klass.class_func(2).(3,4).should == 9
|
69
|
+
end
|
70
|
+
|
71
|
+
it "allows declaring new methods on an instance" do
|
72
|
+
klass.pattern(:new_func).with(:a, :b).returns(:c)
|
73
|
+
klass.pattern(:new_func).with(:d, :e).returns(:f)
|
74
|
+
|
75
|
+
klass.new_func(:a).(:b).should == :c
|
76
|
+
klass.new_func(:d,:e).should == :f
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pattern-proc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- William Pleasant-Ryan
|
@@ -23,6 +23,7 @@ files:
|
|
23
23
|
- README.md
|
24
24
|
- lib/pattern_proc.rb
|
25
25
|
- pattern-proc.gemspec
|
26
|
+
- spec/lib/object_method_spec.rb
|
26
27
|
- spec/lib/pattern_proc_spec.rb
|
27
28
|
homepage: http://rubygems.org/gems/pattern-proc
|
28
29
|
licenses:
|