call-me 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []