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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5d5feb7784773d21a7a6cfd9004f771d8626d9c5
4
- data.tar.gz: 9378aa295eb70fed4f8f3421bd8adfc22a611e0d
3
+ metadata.gz: adc2ed80e8a4406782666406fd1cda3117de27ad
4
+ data.tar.gz: 14792f45f789de53c59a60cf429d1d8e86151645
5
5
  SHA512:
6
- metadata.gz: 2eb70413d2a4614ff8f9daa48071600d82a139f03fad5652b522280ed727451bb08bb2932ebe65bb1eea4d866eaf14458e4668cd56b338fa41b2427c8d997678
7
- data.tar.gz: 311757068e3e8eaf2bd414e244bf55101f548118f2403f2085d1b1178e4260b727694f130aaccee6bdba11ede13e2805a282ea60bc1f8bab67a2a992023963db
6
+ metadata.gz: f18e19c8a4ad26628d01f35179f94aad549d9ea350c15fb6880524e0406a15758e1c52de4baf5dfb9379ba766c95761b755b692c8957cac33433e95444667c05
7
+ data.tar.gz: 4fcdedf9e878868403999bdd127d216d60b4030b90a3a5cb8f4b65f6a1b409de132a3a39b59ec5529f375e4e8d268fbdbdce3dc8e9bd04b477f3468027e400a5
data/Gemfile CHANGED
@@ -2,4 +2,6 @@ source "https://rubygems.org"
2
2
 
3
3
  group :test do
4
4
  gem "rspec"
5
+ gem "pry"
6
+ gem "metaclass"
5
7
  end
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
- class PatternProc
1
+ require 'metaclass'
2
2
 
3
- def initialize(cases = [])
4
- @arity = -1
5
- @cases = []
6
- cases.each do |c| add_case c end
3
+ module PatternProc
4
+ def self.included(klass)
5
+ klass.extend ClassMethods
6
+ Object.include ObjectMethods
7
7
  end
8
8
 
9
- def with(*args, &block)
10
- case_obj = PatternProcCase.new(args, &block)
11
- add_case case_obj
12
- case_obj
13
- end
9
+ class PatternProc
14
10
 
15
- def to_proc
16
- ->(*args) { call(args) }
17
- end
11
+ def initialize(cases = [])
12
+ @arity = -1
13
+ @cases = []
14
+ cases.each do |c| add_case c end
15
+ end
18
16
 
19
- private
20
- def add_case(case_obj)
21
- if @arity == -1
22
- @arity = case_obj.arity
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
- def call(args)
31
- if args.size == @arity
32
- best_match = find_matches(args, true).first
33
- if best_match
34
- best_match.to_proc.call(args)
35
- else
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
- elsif args.size < @arity
39
- sliced_cases = find_matches(args, false)
40
- if sliced_cases.size > 0
41
- PatternProc.new(sliced_cases).to_proc
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 "no match"
54
+ raise "too many args"
44
55
  end
45
- else
46
- raise "too many args"
47
56
  end
48
- end
49
57
 
50
- def find_matches(args, stop_at_first_match)
51
- results = []
52
- sorted_cases = @cases.sort do |case_obj_1, case_obj_2|
53
- case_obj_1.specificity <=> case_obj_2.specificity
54
- end.reverse
55
- sorted_cases.each do |case_obj|
56
- result = case_obj.make_subcase(args)
57
- if result
58
- results << result
59
- if stop_at_first_match
60
- break
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
- attr_reader :proc_applied_level
71
- attr_reader :proc_arity
78
+ attr_reader :proc_applied_level
79
+ attr_reader :proc_arity
72
80
 
73
- def initialize(args, previous_specificity = 0, proc_arity = 0, &block)
74
- @expected_args = args
75
- @proc = block
76
- @proc_arity = proc_arity
77
- @previous_specificity = previous_specificity || 0
78
- if !block.nil? && block.arity > 0
79
- @proc_arity = block.arity
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
- def returns(value)
84
- @return_value = value
85
- self
86
- end
91
+ def returns(value)
92
+ @return_value = value
93
+ self
94
+ end
87
95
 
88
- # private ish
89
- def expected_arity
90
- @expected_args.size || 0
91
- end
96
+ # private ish
97
+ def expected_arity
98
+ @expected_args.size || 0
99
+ end
92
100
 
93
- def arity
94
- expected_arity + proc_arity
95
- end
101
+ def arity
102
+ expected_arity + proc_arity
103
+ end
96
104
 
97
- def specificity
98
- expected_arity + @previous_specificity
99
- end
105
+ def specificity
106
+ expected_arity + @previous_specificity
107
+ end
100
108
 
101
- def make_subcase(args)
102
- match_len = [args.size, @expected_args.size].min
103
- expected = @expected_args.take(match_len)
104
- actual = args.take(match_len)
105
- if expected == actual
106
- new_proc = to_proc.curry
107
- curry_count = args.size - @expected_args.size
108
- new_arity = proc_arity
109
- if curry_count > 0
110
- send_args = args.drop(match_len).take(curry_count)
111
- new_proc = new_proc.call(*send_args)
112
- new_arity -= curry_count
113
- if new_arity == 0
114
- return PatternProcCase.new([], specificity).returns(new_proc)
115
- elsif !(new_proc.is_a?(Proc))
116
- raise "uh oh"
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
- def to_proc
126
- @proc || ->(*args) { @return_value }
133
+ def to_proc
134
+ @proc || ->(*args) { @return_value }
135
+ end
127
136
  end
128
- end
129
137
 
130
- class Object
131
- def partials(method)
132
- @__partials ||= {}
133
- unless @__partials[method]
134
- proc_obj = PatternProc.new
135
- metaclass = class << self; self; end
136
- metaclass.class_eval do
137
- define_method(method) do |*args|
138
- curried_method = proc_obj.to_proc.curry
139
- curried_method[*args]
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
- @__partials[method] = proc_obj
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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'pattern-proc'
3
- s.version = '0.0.3'
3
+ s.version = '0.0.4'
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'
@@ -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
@@ -1,6 +1,6 @@
1
1
  require 'pattern_proc'
2
2
 
3
- describe PatternProc do
3
+ describe PatternProc::PatternProc do
4
4
  subject { described_class.new }
5
5
 
6
6
  it "simple" do
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.3
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: