pattern-proc 0.0.4 → 0.0.6

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 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