call-me 0.0.1

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.
@@ -0,0 +1,109 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ require 'refining'
12
+
13
+ class Module
14
+ refine_method :method_added, :prefix => '__memoize' do |name|
15
+ next if name == 'temporary method for refining'
16
+
17
+ memoize(name) if @__to_memoize__
18
+
19
+ __memoize_method_added(name)
20
+ end
21
+
22
+ refine_method :singleton_method_added, :prefix => '__memoize' do |name|
23
+ next if name == 'temporary method for refining'
24
+
25
+ singleton_memoize(name) if @__to_singleton_memoize__
26
+
27
+ __memoize_singleton_method_added(name)
28
+ end
29
+ end
30
+
31
+ class Object
32
+ def is_memoized? (name)
33
+ respond_to? "__memoize_#{name}"
34
+ end
35
+
36
+ # Memoize the method +name+.
37
+ def memoize (name = nil)
38
+ return if @__to_memoize__ = !name
39
+
40
+ to_call = "__memoize_#{name}"
41
+
42
+ begin; if instance_method(name).arity == 0
43
+ refine_method name, :prefix => '__memoize' do
44
+ (memoize_cache[name][nil] ||= [__send__(to_call)])[0]
45
+ end
46
+
47
+ return
48
+ end; rescue; end
49
+
50
+ refine_method name, :prefix => '__memoize' do |*args|
51
+ if tmp = memoize_cache[name][args]
52
+ tmp
53
+ else
54
+ memoize_cache[name][__memoize_try_to_clone__(args)] = [__send__(*([to_call] + args))]
55
+ end[0]
56
+ end
57
+
58
+ nil
59
+ end
60
+
61
+ # Memoize the singleton method +name+.
62
+ def singleton_memoize (name = nil)
63
+ return if @__to_singleton_memoize__ = !name
64
+
65
+ to_call = "__memoize_#{name}"
66
+
67
+ begin; if method(name).arity == 0
68
+ refine_singleton_method name, :prefix => '__memoize' do
69
+ (memoize_cache[name][nil] ||= [__send__(to_call)])[0]
70
+ end
71
+
72
+ return
73
+ end; rescue; end
74
+
75
+ refine_singleton_method name, :prefix => '__memoize' do |*args, &block|
76
+ if tmp = memoize_cache[name][args]
77
+ tmp
78
+ else
79
+ memoize_cache[name][__memoize_try_to_clone__(args)] = [__send__(*([to_call] + args))]
80
+ end[0]
81
+ end
82
+
83
+ nil
84
+ end; alias singleton_memoize singleton_memoize
85
+
86
+ # Clear the memoize cache completely or only for the method +name+
87
+ def memoize_clear (name = nil)
88
+ if name
89
+ memoize_cache.delete(name.to_sym)
90
+ else
91
+ memoize_cache.clear
92
+ end
93
+ end; alias memoize_clear memoize_clear
94
+
95
+ # Get the memoization cache
96
+ def memoize_cache
97
+ @__memoize_cache__ ||= Hash.new { |h, k| h[k] = {} }
98
+ end; alias memoize_cache memoize_cache
99
+
100
+ private
101
+
102
+ def __memoize_try_to_clone__ (value) # :nodoc:
103
+ begin
104
+ Marshal.load(Marshal.dump(value))
105
+ rescue Exception
106
+ value
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,242 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ require 'refining'
12
+
13
+ class Named
14
+ @warn = true
15
+
16
+ def self.warn (value)
17
+ @warn = value
18
+ end
19
+
20
+ def self.warn?
21
+ @warn
22
+ end
23
+
24
+ def initialize (name)
25
+ @name = name.to_sym
26
+ end
27
+
28
+ def to_sym
29
+ @name
30
+ end
31
+
32
+ def self.normalize (*args)
33
+ options = Hash[
34
+ :optional => [],
35
+ :alias => {},
36
+ :rest => []
37
+ ].merge(args.last.is_a?(Hash) ? args.pop : {})
38
+
39
+ method = args.shift.to_sym
40
+ names = args
41
+
42
+ options[:optional] = Hash[if options[:optional].is_a?(Range)
43
+ names[options[:optional]]
44
+ elsif options[:optional].is_a?(Hash)
45
+ [options[:optional]]
46
+ else
47
+ options[:optional]
48
+ end.map {|opt|
49
+ if opt.is_a?(Hash)
50
+ opt.to_a
51
+ else
52
+ [[opt, nil]]
53
+ end
54
+ }.flatten(1)]
55
+
56
+ return method, names, options
57
+ end
58
+
59
+ def self.arguments (names, options, *args)
60
+ return args if (args.length != 1 || !args.first.is_a?(Hash)) || (options[:rest] && !args.last.is_a?(Hash))
61
+
62
+ parameters = args.pop
63
+ rest = args
64
+ args = []
65
+
66
+ # fix alias parameters
67
+ parameters.dup.each {|name, value|
68
+ if options[:alias].has_key?(name)
69
+ parameters[options[:alias][name]] = value
70
+ parameters.delete(name)
71
+ elsif name.is_a?(Integer) && !parameters[names[name - 1]].is_a?(Integer)
72
+ parameters[names[name - 1]] = value
73
+ parameters.delete(name)
74
+ end
75
+ }
76
+
77
+ # check if there are unknown parameters
78
+ parameters.keys.each {|parameter|
79
+ raise ArgumentError, "#{parameter} is an unknown parameter" unless names.member?(parameter)
80
+ }
81
+
82
+ # check for missing required parameters
83
+ (names - parameters.keys - options[:optional].keys).tap {|required|
84
+ raise ArgumentError, "the following required parameters are missing: #{required.join(', ')}" unless required.empty?
85
+ } unless options[:optional] == true
86
+
87
+ all_optional_after = names.length - names.reverse.take_while {|name|
88
+ options[:optional].has_key?(name) && !parameters.has_key?(name)
89
+ }.length
90
+
91
+ # fill the arguments array
92
+ # TODO: try to not add nil for the last optional parameters
93
+ names.each_with_index {|name, index|
94
+ if parameters.has_key?(name)
95
+ if options[:rest].member?(name)
96
+ args.push(*parameters[name])
97
+ else
98
+ args << parameters[name]
99
+ end
100
+ else
101
+ if index < all_optional_after
102
+ warn 'keep in mind that optionals between two arguments will have nil as value' if Named.warn?
103
+ end
104
+
105
+ if options[:optional][name].nil? && index >= all_optional_after
106
+ break
107
+ end
108
+
109
+ args << options[:optional][name]
110
+ end
111
+ }
112
+
113
+ args
114
+ end
115
+
116
+ def self.definition (method)
117
+ names = []
118
+ options = { :rest => [], :optional => [] }
119
+
120
+ if method.respond_to? :parameters
121
+ method.parameters.map {|how, name|
122
+ if name
123
+ names << name
124
+
125
+ options[:optional] << name if how == :opt
126
+ options[:rest] << name if how == :rest
127
+ else
128
+ names << rand.to_s
129
+ options[:rest] << names.last
130
+ end
131
+ }
132
+ else
133
+ if method.arity > 0
134
+ names.push(*(1 .. method.arity))
135
+ end
136
+ end
137
+
138
+ [names, options]
139
+ end
140
+ end
141
+
142
+ module Kernel
143
+ def always_named!
144
+ @always_named = true
145
+ end
146
+
147
+ def always_named?
148
+ @always_named
149
+ end
150
+ end
151
+
152
+ class Module
153
+ refine_method :method_added, prefix: '__named' do |name|
154
+ next if name == 'temporary method for refining'
155
+
156
+ @__named_last_method__ = name
157
+
158
+ if @__to_namedify__
159
+ named(Named.new(@__named_last_method__), *@__to_namedify__)
160
+ elsif always_named?
161
+ namedc(nil)
162
+ end
163
+
164
+ __named_method_added(name)
165
+ end
166
+
167
+ refine_method :singleton_method_added, prefix: '__named' do |name|
168
+ next if name == 'temporary method for refining'
169
+
170
+ @__singleton_named_last_method__ = name
171
+
172
+ if @__to_singleton_namedify__
173
+ singleton_named(Named.new(@__singleton_named_last_method__), *@__to_singleton_namedify__)
174
+ elsif always_named?
175
+ singleton_named(nil)
176
+ end
177
+
178
+ __named_singleton_method_added(name)
179
+ end
180
+ end
181
+
182
+ class Object
183
+ def named (*args)
184
+ raise ArgumentError, 'you have to pass at least one argument' if args.length == 0
185
+
186
+ if args.first.nil?
187
+ if @__named_last_method__
188
+ names, options = Named.definition(instance_method(@__named_last_method__))
189
+
190
+ named(Named.new(@__named_last_method__), *(names + [options]))
191
+ end; true
192
+ elsif !args.first.is_a?(Named)
193
+ @__to_namedify__ = args
194
+ end and return
195
+
196
+ @__to_namedify__ = false
197
+
198
+ method, names, options = Named.normalize(*args)
199
+
200
+ instance_method(method).tap {|m|
201
+ raise ArgumentError, 'method arity mismatch' if m.arity > 0 && m.arity != names.length
202
+ }
203
+
204
+ to_call = "__named_#{method}"
205
+
206
+ refine_method method, :prefix => '__named' do |*args, &block|
207
+ __send__ *([to_call] + Named.arguments(names, options, *args)), &block
208
+ end
209
+
210
+ nil
211
+ end
212
+
213
+ def singleton_named (*args)
214
+ raise ArgumentError, 'you have to pass at least one argument' if args.length == 0
215
+
216
+ if args.first.nil?
217
+ if @__singleton_named_last_method__
218
+ names, options = Named.definition(method(@__singleton_named_last_method__))
219
+
220
+ singleton_named(Named.new(@__singleton_named_last_method__), *(names + [options]))
221
+ end; true
222
+ elsif !args.first.is_a?(Named)
223
+ @__to_singleton_namedify__ = args
224
+ end and return
225
+
226
+ @__to_singleton_namedify__ = false
227
+
228
+ method, names, options = Named.normalize(*args)
229
+
230
+ method(method).tap {|m|
231
+ raise ArgumentError, 'method arity mismatch' if m.arity > 0 && m.arity != names.length
232
+ }
233
+
234
+ to_call = "__named_#{method}"
235
+
236
+ refine_singleton_method method, :prefix => '__named' do |*args, &block|
237
+ __send__ *([to_call] + Named.arguments(names, options, *args)), &block
238
+ end
239
+
240
+ nil
241
+ end
242
+ end
@@ -0,0 +1,76 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ require 'refining'
12
+
13
+ class Module
14
+ private
15
+
16
+ def __overload (name)
17
+ overloaded = (__overloaded__[name] ||= {})
18
+ overloaded[@__to_overload__ || :default] = instance_method(name)
19
+
20
+ remove_instance_variable :@__to_overload__
21
+
22
+ define_method name do |*args, &block|
23
+ overloaded.each {|signature, body|
24
+ next if signature == :default || signature.each_with_index.any? {|klass, index|
25
+ !args[index].is_a?(klass)
26
+ }
27
+
28
+ return body.bind(self).call(*args, &block)
29
+ }
30
+
31
+ return overloaded[:default].bind(self).call(*args, &block) if overloaded[:default]
32
+
33
+ raise ArgumentError, "the arguments don't match any signature"
34
+ end
35
+ end
36
+
37
+ def __overloaded__
38
+ @__overloaded__ ||= {}
39
+ end
40
+
41
+ public
42
+
43
+ def is_overloaded? (name)
44
+ __overloaded__.has_key?(name)
45
+ end
46
+
47
+ def def_signature (*sign)
48
+ @__to_overload__ = sign
49
+ end
50
+
51
+ def define_overloadable (name, default = nil, matchers)
52
+ define_method name do |*args|
53
+ matchers.each {|signature, body|
54
+ return instance_exec *args, &body if (signature.is_a?(Array) ? signature : [signature]).each_with_index.all? {|klass, index|
55
+ args[index].is_a?(klass)
56
+ }
57
+ }
58
+
59
+ return instance_exec *args, &default if default
60
+
61
+ raise ArgumentError, "the arguments don't match any signature"
62
+ end
63
+ end
64
+
65
+ refine_method :method_added, :prefix => '__overload' do |name|
66
+ next if name == 'temporary method for refining'
67
+
68
+ if !@__overloading__ && (@__to_overload__ || is_overloaded?(name))
69
+ @__overloading__ = true
70
+ __overload(name)
71
+ remove_instance_variable :@__overloading__
72
+ end
73
+
74
+ __overload_method_added(name)
75
+ end
76
+ end
@@ -0,0 +1,43 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ class Module
12
+ private
13
+
14
+ public
15
+
16
+ def define_pattern_matched (name, default = nil, matchers)
17
+ define_method name do |*args|
18
+ matchers.each {|signature, body|
19
+ if signature.is_a?(Proc)
20
+ return instance_exec *args, &body if signature.call(*args)
21
+ else
22
+ return instance_exec *args, &body if (signature.is_a?(Array) ? signature : [signature]) == args
23
+ end
24
+ }
25
+
26
+ return instance_exec *args, &default if default
27
+
28
+ raise ArgumentError, "non-exhaustive patterns"
29
+ end
30
+ end
31
+
32
+ refine_method :method_added, :prefix => '__pattern_match' do |name|
33
+ next if name == 'temporary method for refining'
34
+
35
+ if !@__pattern_matching__ && (@__to_pattern_match__ || is_pattern_matched?(name))
36
+ @__pattern_matching__ = true
37
+ __pattern_match(name)
38
+ remove_instance_variable :@__pattern_matching__
39
+ end
40
+
41
+ __pattern_match_method_added(name)
42
+ end
43
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: call-me
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - meh.
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: refining
16
+ requirement: &9935540 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *9935540
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &9934600 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *9934600
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &9933640 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *9933640
47
+ description:
48
+ email: meh@paranoici.org
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - lib/call-me/pattern-matching.rb
54
+ - lib/call-me/named.rb
55
+ - lib/call-me/overload.rb
56
+ - lib/call-me/memoize.rb
57
+ homepage: http://github.com/meh/ruby-call-me
58
+ licenses: []
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 1.8.10
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Various calling things, overload, pattern matching, memoization and such.
81
+ test_files: []