pattern-proc 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: adc2ed80e8a4406782666406fd1cda3117de27ad
4
- data.tar.gz: 14792f45f789de53c59a60cf429d1d8e86151645
3
+ metadata.gz: 2e6e5c92ff2acd52f48ad6a3499622f6b6605ce3
4
+ data.tar.gz: 48d17c98cf20548f02d4fb5a317c412235c22c3c
5
5
  SHA512:
6
- metadata.gz: f18e19c8a4ad26628d01f35179f94aad549d9ea350c15fb6880524e0406a15758e1c52de4baf5dfb9379ba766c95761b755b692c8957cac33433e95444667c05
7
- data.tar.gz: 4fcdedf9e878868403999bdd127d216d60b4030b90a3a5cb8f4b65f6a1b409de132a3a39b59ec5529f375e4e8d268fbdbdce3dc8e9bd04b477f3468027e400a5
6
+ metadata.gz: 331e688e706805d3e03687107141f45b2652f8c0e568c02c79bdd3de0de7e7c0c78b4764708da4968d8215cdb288563f5a5d6ab13438e0315f82b3d59ce6bb4e
7
+ data.tar.gz: acbdae026983fe1db56d77a1b88fd0aeca837980eb9637a5ccf421dcf03f2c1cf47b4ca26b92804959909838da7018f34bb60162f2fce614e3166d28da40aa4e
@@ -0,0 +1,14 @@
1
+ module PatternProc
2
+ module ClassMethods
3
+ def self.included(klass)
4
+ klass.extend JustClassMethods
5
+ end
6
+ end
7
+
8
+ module JustClassMethods
9
+ def pattern(method)
10
+ @__patterns ||= {}
11
+ PatternProcPatterns.find_or_create_pattern @__patterns, self, method
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ module PatternProc
2
+ module ObjectMethods
3
+ private
4
+ end
5
+ end
@@ -0,0 +1,70 @@
1
+ require 'pattern-proc/pattern_proc_case'
2
+
3
+ module PatternProc
4
+ class PatternProc
5
+
6
+ def initialize(cases = [])
7
+ @arity = -1
8
+ @cases = []
9
+ cases.each do |c| add_case c end
10
+ end
11
+
12
+ def with(*args, &block)
13
+ case_obj = PatternProcCase.new(args, &block)
14
+ add_case case_obj
15
+ case_obj
16
+ end
17
+
18
+ def to_proc
19
+ ->(*args) { call(args) }
20
+ end
21
+
22
+ private
23
+ def add_case(case_obj)
24
+ if @arity == -1
25
+ @arity = case_obj.arity
26
+ elsif @arity != case_obj.arity
27
+ raise "mismatched arity"
28
+ end
29
+ @cases << case_obj
30
+ end
31
+
32
+
33
+ def call(args)
34
+ if args.size == @arity
35
+ best_match = find_matches(args, true).first
36
+ if best_match
37
+ best_match.to_proc.call(args)
38
+ else
39
+ raise "no match"
40
+ end
41
+ elsif args.size < @arity
42
+ sliced_cases = find_matches(args, false)
43
+ if sliced_cases.size > 0
44
+ PatternProc.new(sliced_cases).to_proc
45
+ else
46
+ raise "no match"
47
+ end
48
+ else
49
+ raise "too many args"
50
+ end
51
+ end
52
+
53
+ def find_matches(args, stop_at_first_match)
54
+ results = []
55
+ sorted_cases = @cases.sort do |case_obj_1, case_obj_2|
56
+ case_obj_1.specificity <=> case_obj_2.specificity
57
+ end.reverse
58
+ sorted_cases.each do |case_obj|
59
+ result = case_obj.make_subcase(args)
60
+ if result
61
+ results << result
62
+ if stop_at_first_match
63
+ break
64
+ end
65
+ end
66
+ end
67
+ results
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,63 @@
1
+ module PatternProc
2
+ class PatternProcCase
3
+
4
+ attr_reader :proc_applied_level
5
+ attr_reader :proc_arity
6
+
7
+ def initialize(args, previous_specificity = 0, proc_arity = 0, &block)
8
+ @expected_args = args
9
+ @proc = block
10
+ @proc_arity = proc_arity
11
+ @previous_specificity = previous_specificity || 0
12
+ if !block.nil? && block.arity > 0
13
+ @proc_arity = block.arity
14
+ end
15
+ end
16
+
17
+ def returns(value)
18
+ @return_value = value
19
+ self
20
+ end
21
+
22
+ # private ish
23
+ def expected_arity
24
+ @expected_args.size || 0
25
+ end
26
+
27
+ def arity
28
+ expected_arity + proc_arity
29
+ end
30
+
31
+ def specificity
32
+ expected_arity + @previous_specificity
33
+ end
34
+
35
+ def make_subcase(args)
36
+ match_len = [args.size, @expected_args.size].min
37
+ expected = @expected_args.take(match_len)
38
+ actual = args.take(match_len)
39
+ if expected == actual
40
+ new_proc = to_proc.curry
41
+ curry_count = args.size - @expected_args.size
42
+ new_arity = proc_arity
43
+ if curry_count > 0
44
+ send_args = args.drop(match_len).take(curry_count)
45
+ new_proc = new_proc.call(*send_args)
46
+ new_arity -= curry_count
47
+ if new_arity == 0
48
+ return PatternProcCase.new([], specificity).returns(new_proc)
49
+ elsif !(new_proc.is_a?(Proc))
50
+ raise "uh oh"
51
+ end
52
+ end
53
+ PatternProcCase.new(@expected_args.drop(match_len), specificity, new_arity, &new_proc).returns(@return_value)
54
+ else
55
+ nil
56
+ end
57
+ end
58
+
59
+ def to_proc
60
+ @proc || ->(*args) { @return_value }
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,21 @@
1
+ require 'pattern-proc/pattern_proc'
2
+
3
+ module PatternProc
4
+ class PatternProcPatterns
5
+ class << self
6
+ def find_or_create_pattern(patterns, receiver, method)
7
+ unless patterns[method]
8
+ proc_obj = PatternProc.new
9
+ receiver.class_eval do
10
+ define_method(method) do |*args|
11
+ curried_method = proc_obj.to_proc.curry
12
+ curried_method[*args]
13
+ end
14
+ end
15
+ patterns[method] = proc_obj
16
+ end
17
+ patterns[method]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ require 'metaclass'
2
+
3
+ module PatternProc
4
+ module TestMethods
5
+ def pattern(method)
6
+ @__patterns ||= {}
7
+ PatternProcPatterns.find_or_create_pattern @__patterns, self.__metaclass__, method
8
+ end
9
+ end
10
+ end
data/lib/pattern_proc.rb CHANGED
@@ -1,167 +1,6 @@
1
- require 'metaclass'
1
+ require 'pattern-proc/pattern_proc'
2
+ require 'pattern-proc/pattern_proc_patterns'
3
+ require 'pattern-proc/object_methods'
4
+ require 'pattern-proc/class_methods'
5
+ require 'pattern-proc/test_methods'
2
6
 
3
- module PatternProc
4
- def self.included(klass)
5
- klass.extend ClassMethods
6
- Object.include ObjectMethods
7
- end
8
-
9
- class PatternProc
10
-
11
- def initialize(cases = [])
12
- @arity = -1
13
- @cases = []
14
- cases.each do |c| add_case c end
15
- end
16
-
17
- def with(*args, &block)
18
- case_obj = PatternProcCase.new(args, &block)
19
- add_case case_obj
20
- case_obj
21
- end
22
-
23
- def to_proc
24
- ->(*args) { call(args) }
25
- end
26
-
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"
33
- end
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
53
- else
54
- raise "too many args"
55
- end
56
- end
57
-
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
70
- end
71
- end
72
- results
73
- end
74
- end
75
-
76
- class PatternProcCase
77
-
78
- attr_reader :proc_applied_level
79
- attr_reader :proc_arity
80
-
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
89
- end
90
-
91
- def returns(value)
92
- @return_value = value
93
- self
94
- end
95
-
96
- # private ish
97
- def expected_arity
98
- @expected_args.size || 0
99
- end
100
-
101
- def arity
102
- expected_arity + proc_arity
103
- end
104
-
105
- def specificity
106
- expected_arity + @previous_specificity
107
- end
108
-
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
126
- end
127
- PatternProcCase.new(@expected_args.drop(match_len), specificity, new_arity, &new_proc).returns(@return_value)
128
- else
129
- nil
130
- end
131
- end
132
-
133
- def to_proc
134
- @proc || ->(*args) { @return_value }
135
- end
136
- end
137
-
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
154
- end
155
- @__pattern[method] = proc_obj
156
- end
157
- @__pattern[method]
158
- end
159
-
160
- end
161
-
162
- module ClassMethods
163
- def pattern(method)
164
- find_or_create_pattern self, method
165
- end
166
- end
167
- end
data/pattern-proc.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'pattern-proc'
3
- s.version = '0.0.4'
3
+ s.version = '0.0.6'
4
4
  s.date = '2014-07-01'
5
5
  s.summary = 'Pattern Proc'
6
6
  s.description = 'define a Proc with pattern matching "re-declaration" ala Haskell'
@@ -1,7 +1,8 @@
1
1
  require 'pattern_proc'
2
+ include PatternProc::TestMethods
2
3
 
3
4
  class TestObjectClass
4
- include PatternProc
5
+ include PatternProc::ClassMethods
5
6
  def my_func(a,b,c)
6
7
  raise "don't call me"
7
8
  end
@@ -12,7 +13,7 @@ end
12
13
 
13
14
  class TestSingletonClass
14
15
  class << self
15
- include PatternProc
16
+ include PatternProc::ClassMethods
16
17
  def class_func(a,b,c)
17
18
  raise "don't call me"
18
19
  end
@@ -22,8 +23,16 @@ class TestSingletonClass
22
23
  end
23
24
  end
24
25
 
26
+ class TestSingletonNoInclude
27
+ class << self
28
+ def a_func(a,b,c)
29
+ raise "don't call me"
30
+ end
31
+ end
32
+ end
33
+
25
34
  describe "pattern object methods" do
26
- context "class" do
35
+ context "object" do
27
36
  let (:obj) { TestObjectClass.new }
28
37
  context "in declaration" do
29
38
  it "allows declaration of pattern methods in a class" do
@@ -50,7 +59,7 @@ describe "pattern object methods" do
50
59
  end
51
60
  end
52
61
 
53
- context "object" do
62
+ context "class" do
54
63
  let (:klass) { TestSingletonClass }
55
64
  context "in declaration" do
56
65
  it "allows declaration of pattern class methods in a class" do
@@ -77,4 +86,15 @@ describe "pattern object methods" do
77
86
  end
78
87
  end
79
88
  end
89
+
90
+ context "for testing" do
91
+ let (:klass) { TestSingletonNoInclude }
92
+ it "allows replacing methods on a class" do
93
+ klass.pattern(:a_func).with(1,2,3).returns(7)
94
+ klass.pattern(:a_func).with(2,3,4).returns(9)
95
+
96
+ klass.a_func(1,2).(3).should == 7
97
+ klass.a_func(2).(3,4).should == 9
98
+ end
99
+ end
80
100
  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
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Pleasant-Ryan
@@ -21,6 +21,12 @@ files:
21
21
  - Gemfile.lock
22
22
  - LICENSE
23
23
  - README.md
24
+ - lib/pattern-proc/class_methods.rb
25
+ - lib/pattern-proc/object_methods.rb
26
+ - lib/pattern-proc/pattern_proc.rb
27
+ - lib/pattern-proc/pattern_proc_case.rb
28
+ - lib/pattern-proc/pattern_proc_patterns.rb
29
+ - lib/pattern-proc/test_methods.rb
24
30
  - lib/pattern_proc.rb
25
31
  - pattern-proc.gemspec
26
32
  - spec/lib/object_method_spec.rb