quality_extensions 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Readme +54 -0
- data/lib/qualitysmith_extensions/all.rb +4 -0
- data/lib/qualitysmith_extensions/array/all.rb +2 -0
- data/lib/qualitysmith_extensions/array/average.rb +44 -0
- data/lib/qualitysmith_extensions/array/classify.rb +97 -0
- data/lib/qualitysmith_extensions/array/expand_ranges.rb +52 -0
- data/lib/qualitysmith_extensions/array/group_by.rb +134 -0
- data/lib/qualitysmith_extensions/array/sequence.rb +66 -0
- data/lib/qualitysmith_extensions/array/shell_escape.rb +36 -0
- data/lib/qualitysmith_extensions/array/to_a_recursive.rb +41 -0
- data/lib/qualitysmith_extensions/array/to_query_string.rb +96 -0
- data/lib/qualitysmith_extensions/collection_extensions_for_cgi.rb +2 -0
- data/lib/qualitysmith_extensions/colored/toggleability.rb +62 -0
- data/lib/qualitysmith_extensions/console/command.facets.1.8.51.rb +749 -0
- data/lib/qualitysmith_extensions/console/command.facets.1.8.54.rb +748 -0
- data/lib/qualitysmith_extensions/console/command.rb +944 -0
- data/lib/qualitysmith_extensions/date/all.rb +2 -0
- data/lib/qualitysmith_extensions/date/deprecated.rb +40 -0
- data/lib/qualitysmith_extensions/date/iso8601.rb +31 -0
- data/lib/qualitysmith_extensions/date/month_ranges.rb +122 -0
- data/lib/qualitysmith_extensions/dir/each_child.rb +58 -0
- data/lib/qualitysmith_extensions/enumerable/enum.rb +69 -0
- data/lib/qualitysmith_extensions/enumerable/select_until.rb +4 -0
- data/lib/qualitysmith_extensions/enumerable/select_while.rb +109 -0
- data/lib/qualitysmith_extensions/exception/inspect_with_backtrace.rb +65 -0
- data/lib/qualitysmith_extensions/file/exact_match_regexp.rb +34 -0
- data/lib/qualitysmith_extensions/file_test/binary_file.rb +110 -0
- data/lib/qualitysmith_extensions/find/select.rb +68 -0
- data/lib/qualitysmith_extensions/global_variable_set.rb +153 -0
- data/lib/qualitysmith_extensions/hash/all.rb +2 -0
- data/lib/qualitysmith_extensions/hash/to_date.rb +34 -0
- data/lib/qualitysmith_extensions/hash/to_query_string.rb +121 -0
- data/lib/qualitysmith_extensions/kernel/all.rb +2 -0
- data/lib/qualitysmith_extensions/kernel/autoreload.rb +128 -0
- data/lib/qualitysmith_extensions/kernel/backtrace.rb +71 -0
- data/lib/qualitysmith_extensions/kernel/capture_output.rb +115 -0
- data/lib/qualitysmith_extensions/kernel/die.rb +49 -0
- data/lib/qualitysmith_extensions/kernel/example_printer.rb +81 -0
- data/lib/qualitysmith_extensions/kernel/filter_output.rb +108 -0
- data/lib/qualitysmith_extensions/kernel/remove_const.rb +178 -0
- data/lib/qualitysmith_extensions/kernel/remove_module.rb +127 -0
- data/lib/qualitysmith_extensions/kernel/require_all.rb +186 -0
- data/lib/qualitysmith_extensions/kernel/require_local_all.rb +4 -0
- data/lib/qualitysmith_extensions/kernel/require_once.rb +18 -0
- data/lib/qualitysmith_extensions/kernel/simulate_input.rb +52 -0
- data/lib/qualitysmith_extensions/kernel/trap_chain.rb +61 -0
- data/lib/qualitysmith_extensions/kernel/windows_platform.rb +46 -0
- data/lib/qualitysmith_extensions/module/alias_method.rb +6 -0
- data/lib/qualitysmith_extensions/module/alias_method_chain.rb +165 -0
- data/lib/qualitysmith_extensions/module/ancestry_of_instance_method.rb +43 -0
- data/lib/qualitysmith_extensions/module/attribute_accessors.rb +49 -0
- data/lib/qualitysmith_extensions/module/basename.rb +76 -0
- data/lib/qualitysmith_extensions/module/bool_attr_accessor.rb +497 -0
- data/lib/qualitysmith_extensions/module/class_methods.rb +87 -0
- data/lib/qualitysmith_extensions/module/create.rb +315 -0
- data/lib/qualitysmith_extensions/module/create_setter.rb +9 -0
- data/lib/qualitysmith_extensions/module/dirname.rb +4 -0
- data/lib/qualitysmith_extensions/module/guard_method.rb +312 -0
- data/lib/qualitysmith_extensions/module/includable_once.rb +10 -0
- data/lib/qualitysmith_extensions/module/join.rb +66 -0
- data/lib/qualitysmith_extensions/module/malias_method_chain.rb +92 -0
- data/lib/qualitysmith_extensions/module/module_methods.rb +4 -0
- data/lib/qualitysmith_extensions/module/namespace.rb +112 -0
- data/lib/qualitysmith_extensions/module/parents.rb +61 -0
- data/lib/qualitysmith_extensions/module/remove_const.rb +117 -0
- data/lib/qualitysmith_extensions/module/split.rb +55 -0
- data/lib/qualitysmith_extensions/month.rb +66 -0
- data/lib/qualitysmith_extensions/mutex/if_available.rb +75 -0
- data/lib/qualitysmith_extensions/object/ancestry_of_method.rb +257 -0
- data/lib/qualitysmith_extensions/object/default.rb +69 -0
- data/lib/qualitysmith_extensions/object/if_else.rb +157 -0
- data/lib/qualitysmith_extensions/object/ignore_access.rb +84 -0
- data/lib/qualitysmith_extensions/object/mcall.rb +92 -0
- data/lib/qualitysmith_extensions/object/methods.rb +63 -0
- data/lib/qualitysmith_extensions/object/send_if.rb +151 -0
- data/lib/qualitysmith_extensions/object/send_if_not_nil.rb +35 -0
- data/lib/qualitysmith_extensions/object/singleton_send.rb +129 -0
- data/lib/qualitysmith_extensions/regexp/join.rb +111 -0
- data/lib/qualitysmith_extensions/string/all.rb +2 -0
- data/lib/qualitysmith_extensions/string/constantize.rb +4 -0
- data/lib/qualitysmith_extensions/string/digits_only.rb +27 -0
- data/lib/qualitysmith_extensions/string/each_char_with_index.rb +41 -0
- data/lib/qualitysmith_extensions/string/md5.rb +29 -0
- data/lib/qualitysmith_extensions/string/shell_escape.rb +43 -0
- data/lib/qualitysmith_extensions/string/to_underscored_label.rb +37 -0
- data/lib/qualitysmith_extensions/string/with_knowledge_of_color.rb +64 -0
- data/lib/qualitysmith_extensions/symbol/constantize.rb +69 -0
- data/lib/qualitysmith_extensions/symbol/match.rb +157 -0
- data/lib/qualitysmith_extensions/template.rb +33 -0
- data/lib/qualitysmith_extensions/test/all.rb +2 -0
- data/lib/qualitysmith_extensions/test/assert_anything.rb +93 -0
- data/lib/qualitysmith_extensions/test/assert_changed.rb +66 -0
- data/lib/qualitysmith_extensions/test/assert_exception.rb +66 -0
- data/lib/qualitysmith_extensions/test/assert_includes.rb +36 -0
- data/lib/qualitysmith_extensions/test/assert_user_error.rb +37 -0
- data/lib/qualitysmith_extensions/test/difference_highlighting.rb +323 -0
- data/lib/qualitysmith_extensions/time/all.rb +2 -0
- data/lib/qualitysmith_extensions/time/deprecated.rb +31 -0
- data/test/all.rb +16 -0
- metadata +148 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
# Rationale:
|
2
|
+
# The ||= "operator" is often used to set a default value.
|
3
|
+
# var ||= 'default'
|
4
|
+
# Unfortunately, it does not give the desired behavior for when you want to give a default value to a *boolean* (which might have been already initialized to false).
|
5
|
+
# When setting a variable to a default value, we actually only want to set it to the default if it's currently set to *nil*!
|
6
|
+
# This was an attempt to supply that missing method...
|
7
|
+
|
8
|
+
module Kernel
|
9
|
+
def default!(object, default_value)
|
10
|
+
case object
|
11
|
+
when NilClass
|
12
|
+
#object.become default_value
|
13
|
+
#object.replace default_value
|
14
|
+
else
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
class NilClass
|
22
|
+
def default!(default_value)
|
23
|
+
#self.become default_value
|
24
|
+
#self.replace default_value
|
25
|
+
#self = default_value
|
26
|
+
|
27
|
+
# Not sure how to implemnet this! ... without writing/using a C extension that lets me turn a NilClass object into another object.
|
28
|
+
end
|
29
|
+
end
|
30
|
+
class Object
|
31
|
+
def default!(default_value)
|
32
|
+
# This should have no effect on any objects other than instances of NilClass.
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
# _____ _
|
40
|
+
# |_ _|__ ___| |_
|
41
|
+
# | |/ _ \/ __| __|
|
42
|
+
# | | __/\__ \ |_
|
43
|
+
# |_|\___||___/\__|
|
44
|
+
#
|
45
|
+
=begin test
|
46
|
+
require 'test/unit'
|
47
|
+
|
48
|
+
class Foo
|
49
|
+
def do_it(options = {})
|
50
|
+
options[:how_many_times] ||= 3
|
51
|
+
#options[:actually_do_it] ||= true # Doesn't work! What if they explicitly set it to false? We would unconditionally be overriding it with true. We only want to set it to true if it's "not set yet" (if it's nil).
|
52
|
+
options[:actually_do_it].default! true # This is how I'd like to do it. It makes it clear what we're doing (setting a default value).
|
53
|
+
options[:actually_do_it] = true if options[:actually_do_it].nil? # This works, but you have to duplicate the variable name in two places. Plus it's not explicitly clear that true is being used as a *default* value.
|
54
|
+
|
55
|
+
options[:actually_do_it] ? "We did it #{options[:how_many_times]} times" : "We didn't actually do it"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class TheTest < Test::Unit::TestCase
|
60
|
+
def test_false
|
61
|
+
assert_equal "We didn't actually do it", Foo.new.do_it(:actually_do_it => false)
|
62
|
+
end
|
63
|
+
def test_true
|
64
|
+
assert_equal "We did it 3 times", Foo.new.do_it()
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
=end
|
69
|
+
|
@@ -0,0 +1,157 @@
|
|
1
|
+
#--
|
2
|
+
# Author:: Tyler Rick
|
3
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
4
|
+
# License:: Ruby License
|
5
|
+
# Submit to Facets?::
|
6
|
+
# Developer notes::
|
7
|
+
# Changes::
|
8
|
+
#++
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
class Object
|
13
|
+
# Returns +self+ if +condition+; otherwise, returns +else_value+.
|
14
|
+
#
|
15
|
+
# Example:
|
16
|
+
# "Average: #{array.average}". if_else array.size >= 3, ''
|
17
|
+
# That is another way to say this:
|
18
|
+
# array.size >= 3 ? "Average: #{array.average}" : '' )
|
19
|
+
#
|
20
|
+
# Sometimes you want to do 'something unless condition' and you want that whole expression to return '' (or some other value)
|
21
|
+
# if the condition is false, rather than nil, which is what it currently returns.
|
22
|
+
#
|
23
|
+
# *Important*: "+self+" will always be "evaluated". So if the receiver of this message is some _dangerous_ call (has side
|
24
|
+
# effects), then you would be advised to use the normal if/then/else or ?/: constructs instead.
|
25
|
+
#
|
26
|
+
# For example, +method_with_adverse_side_effects+ will be called unconditionally in this case (whether or not +ready?+ returns +false+):
|
27
|
+
# obj.method_with_adverse_side_effects. if_else ready?, NotReady
|
28
|
+
# But it will not be called in this case if +ready?+ returns +false+:
|
29
|
+
# ready? ? obj.method_with_adverse_side_effects : NotReady)
|
30
|
+
#
|
31
|
+
# "Isn't this method useless?" ... Yes, basically. Its main advantage is that it lets you put the condition _after_ the normal
|
32
|
+
# value, which may make it easier to follow the normal execution flow when reading the source.
|
33
|
+
#
|
34
|
+
# This is similar to something I saw in another language (Python?) where a similar syntax is built right into the language. Something like this:
|
35
|
+
# normal_value if condition else else_value
|
36
|
+
#
|
37
|
+
# I thought that was a neat idea so I implemented it as best I could in Ruby.
|
38
|
+
#
|
39
|
+
# This might also be interesting for folks coming from Smalltalk, where +if+ really _is_ just a message that you pass to an
|
40
|
+
# object along with a block (?) to be executed if +condition+ is +true+ and a block to be executed if +condition+ is +false+.
|
41
|
+
#
|
42
|
+
def if(condition, else_value = nil)
|
43
|
+
condition ?
|
44
|
+
self :
|
45
|
+
else_value
|
46
|
+
end
|
47
|
+
alias_method :if_else, :if
|
48
|
+
|
49
|
+
def unless(condition, else_value)
|
50
|
+
!condition ?
|
51
|
+
self :
|
52
|
+
else_value
|
53
|
+
end
|
54
|
+
alias_method :unless_else, :unless
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
# _____ _
|
63
|
+
# |_ _|__ ___| |_
|
64
|
+
# | |/ _ \/ __| __|
|
65
|
+
# | | __/\__ \ |_
|
66
|
+
# |_|\___||___/\__|
|
67
|
+
#
|
68
|
+
=begin test
|
69
|
+
require 'test/unit'
|
70
|
+
|
71
|
+
require 'rubygems'
|
72
|
+
require 'qualitysmith_extensions/array/average'
|
73
|
+
|
74
|
+
class TheTest < Test::Unit::TestCase
|
75
|
+
def test_1
|
76
|
+
array = [1, 2]
|
77
|
+
assert_equal 'not enough values', average(array)
|
78
|
+
assert_equal 'not enough values', average_the_normal_way(array)
|
79
|
+
|
80
|
+
array = [1, 2, 3]
|
81
|
+
assert_equal 'average = 2.0', average(array)
|
82
|
+
assert_equal 'average = 2.0', average_the_normal_way(array)
|
83
|
+
end
|
84
|
+
|
85
|
+
# This way is actually easier to read, so you'd be pretty silly to use if_else in this case!
|
86
|
+
def average_the_normal_way(array)
|
87
|
+
array.size >= 3 ?
|
88
|
+
"average = #{array.average}" :
|
89
|
+
'not enough values'
|
90
|
+
end
|
91
|
+
|
92
|
+
def average(array)
|
93
|
+
"average = #{array.average}".if_else( array.size >= 3, 'not enough values' )
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
def test_2
|
101
|
+
# Sometimes you want to do 'something unless condition' and you want that whole expression to return '' (or some other value)
|
102
|
+
# if the condition is false, rather than nil, which is what it currently returns.
|
103
|
+
assert_equal nil, render_list_the_naive_way([])
|
104
|
+
assert_equal '', render_list_the_long_way([])
|
105
|
+
assert_equal '', render_list([])
|
106
|
+
|
107
|
+
list = ['Alice', 'Malory']
|
108
|
+
|
109
|
+
[
|
110
|
+
render_list_the_naive_way(list),
|
111
|
+
render_list_the_long_way(list),
|
112
|
+
render_list(list),
|
113
|
+
].each {|a|
|
114
|
+
assert_equal '<ul><li>Alice</li><li>Malory</li></ul>', a
|
115
|
+
}
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
def render_list_the_naive_way(list)
|
120
|
+
content_tag(:ul,
|
121
|
+
list.map { |item|
|
122
|
+
content_tag(:li,
|
123
|
+
item
|
124
|
+
)
|
125
|
+
}
|
126
|
+
) unless list.empty?
|
127
|
+
end
|
128
|
+
def render_list_the_long_way(list)
|
129
|
+
unless list.empty?
|
130
|
+
content_tag(:ul,
|
131
|
+
list.map { |item|
|
132
|
+
content_tag(:li,
|
133
|
+
item
|
134
|
+
)
|
135
|
+
}
|
136
|
+
)
|
137
|
+
else
|
138
|
+
''
|
139
|
+
end
|
140
|
+
end
|
141
|
+
def render_list(list)
|
142
|
+
content_tag(:ul,
|
143
|
+
list.map { |item|
|
144
|
+
content_tag(:li,
|
145
|
+
item
|
146
|
+
)
|
147
|
+
}
|
148
|
+
). unless_else list.empty?, ''
|
149
|
+
end
|
150
|
+
|
151
|
+
def content_tag(tag, contents)
|
152
|
+
"<#{tag}>#{contents}</#{tag}>"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
=end
|
156
|
+
|
157
|
+
|
@@ -0,0 +1,84 @@
|
|
1
|
+
#--
|
2
|
+
# Author:: Tyler Rick
|
3
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
4
|
+
# License:: Ruby License
|
5
|
+
# Submit to Facets?:: Yes!
|
6
|
+
# Developer notes:
|
7
|
+
# * Come up with a shorter/better name than ignore_access?
|
8
|
+
# * Other name ideas:
|
9
|
+
# * ignore_private
|
10
|
+
# * access_everything
|
11
|
+
# * access
|
12
|
+
# * sneaky
|
13
|
+
# * rude
|
14
|
+
# * all_public
|
15
|
+
# * public!
|
16
|
+
# * all (like rdoc's --all -- it's too generic for a method name though)
|
17
|
+
# * promiscuous (like rdoc's --promiscuous -- different semantics though)
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'rubygems'
|
21
|
+
require 'facets/more/functor'
|
22
|
+
|
23
|
+
class Object
|
24
|
+
|
25
|
+
# Sends all messages to receiver, bypassing access restrictions, allowing you to call private methods (like class_variable_get) without having to write ugly send() calls.
|
26
|
+
#
|
27
|
+
# o.class.ignore_access.class_variable_set(:@@v, 'new value')
|
28
|
+
# is equivalent to:
|
29
|
+
# o.class.send(:class_variable_set, :@@v, 'new value')
|
30
|
+
#
|
31
|
+
# If you tried to just call the method directly, like this:
|
32
|
+
# o.class.class_variable_set(:@@v, 'new value')
|
33
|
+
# you would get a NoMethodError:
|
34
|
+
# NoMethodError: private method `class_variable_set' called for Klass:Class
|
35
|
+
#
|
36
|
+
def ignore_access
|
37
|
+
@_ignore_access_functor ||= Functor.new do |op,*args|
|
38
|
+
self.send(op,*args)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
alias_method :access, :ignore_access
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# _____ _
|
47
|
+
# |_ _|__ ___| |_
|
48
|
+
# | |/ _ \/ __| __|
|
49
|
+
# | | __/\__ \ |_
|
50
|
+
# |_|\___||___/\__|
|
51
|
+
#
|
52
|
+
=begin test
|
53
|
+
require 'test/unit'
|
54
|
+
|
55
|
+
class TheTest < Test::Unit::TestCase
|
56
|
+
|
57
|
+
# It's not identical to Kernel#meta, as this test proves! (Must run it singly, without other tests.)
|
58
|
+
# def test_meta
|
59
|
+
# require 'rubygems'; require 'facets/core/kernel/meta'
|
60
|
+
# o = Object.new
|
61
|
+
# o.class.meta.class_variable_set(:@@v, 'old value')
|
62
|
+
# assert_equal 'old value', o.class.meta.class_variable_get(:@@v)
|
63
|
+
#
|
64
|
+
# #assert_nothing_raised { o.class.send(:class_variable_get, :@@v) } # Fails!
|
65
|
+
#
|
66
|
+
# assert_equal Object, o.class
|
67
|
+
# o.class.send(:class_variable_set, :@@v, 'new value')
|
68
|
+
# assert_equal 'new value', o.class.send(:class_variable_get, :@@v)
|
69
|
+
# assert_equal 'new value', o.class.meta.class_variable_get(:@@v) # Fails! Still has 'old value'!
|
70
|
+
# end
|
71
|
+
|
72
|
+
def test_1
|
73
|
+
o = Object.new
|
74
|
+
o.class.ignore_access.class_variable_set(:@@v, 'old value')
|
75
|
+
assert_nothing_raised { o.class.send(:class_variable_get, :@@v) }
|
76
|
+
o.class.send(:class_variable_set, :@@v, 'new value')
|
77
|
+
assert_equal 'new value', o.class.ignore_access.class_variable_get(:@@v)
|
78
|
+
assert_equal 'new value', o.class.send(:class_variable_get, :@@v)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
=end
|
84
|
+
|
@@ -0,0 +1,92 @@
|
|
1
|
+
#--
|
2
|
+
# Author:: Tyler Rick
|
3
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
4
|
+
# License:: Ruby License
|
5
|
+
# Submit to Facets?:: Maybe.
|
6
|
+
# Developer notes::
|
7
|
+
#++
|
8
|
+
|
9
|
+
class Object
|
10
|
+
# Calls the method implementation from the module of your choice (+moduule+) on the object of your choice (+self+).
|
11
|
+
#
|
12
|
+
# The only (huge) catch is that +self+ must either be an instance of +moduule+ or have +moduule+ as an ancestor... which severely limits its usefullness. (Compare with singleton_send.)
|
13
|
+
#
|
14
|
+
# It is still useful, though, if you want to call some "original" implementation provided by Kernel (or some other base module) and the people that overrode it didn't play nice and use +alias_method_chain+.
|
15
|
+
#
|
16
|
+
# No matter! If the class of the object you are calling this on has Kernel as an ancestor, then you can call any method from Kernel on this object!
|
17
|
+
#
|
18
|
+
# This implementation is gratefully owed to the folks who wrote PP (/usr/lib/ruby/1.8/pp.rb)
|
19
|
+
def mcall(moduule, message, *args, &block)
|
20
|
+
moduule.instance_method(message).bind(self).call(*args, &block)
|
21
|
+
end
|
22
|
+
alias_method :msend, :mcall
|
23
|
+
end
|
24
|
+
|
25
|
+
# _____ _
|
26
|
+
# |_ _|__ ___| |_
|
27
|
+
# | |/ _ \/ __| __|
|
28
|
+
# | | __/\__ \ |_
|
29
|
+
# |_|\___||___/\__|
|
30
|
+
#
|
31
|
+
=begin test
|
32
|
+
require 'test/unit'
|
33
|
+
require 'rubygems'
|
34
|
+
require 'qualitysmith_extensions/test/assert_exception'
|
35
|
+
require 'qualitysmith_extensions/test/assert_includes'
|
36
|
+
require 'facets/core/module/alias_method_chain'
|
37
|
+
|
38
|
+
|
39
|
+
module MyColorizer
|
40
|
+
def colorize(color = nil)
|
41
|
+
self + " (colorized in #{color})"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
class String
|
45
|
+
def class()
|
46
|
+
'classy'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class TheTest < Test::Unit::TestCase
|
51
|
+
def test_doesnt_work_like_singleton_send
|
52
|
+
# This doesn't quite work the same as singleton_send ...
|
53
|
+
assert_exception(TypeError, lambda { |exception|
|
54
|
+
assert_equal 'bind argument must be an instance of MyColorizer', exception.message
|
55
|
+
}) do
|
56
|
+
"whatever".mcall(MyColorizer, :colorize, :blue)
|
57
|
+
end
|
58
|
+
# self actually has to *be* a MyColorizer for this to work... which severely limits the usefulness of mcall...
|
59
|
+
# Since the whole reason we want this is because we don't want to simply mix in MyColorizer into the base class...
|
60
|
+
end
|
61
|
+
|
62
|
+
module ClassSystem
|
63
|
+
def self.included(base)
|
64
|
+
base.class_eval do
|
65
|
+
alias_method_chain :class, :class_system
|
66
|
+
end
|
67
|
+
end
|
68
|
+
def class_with_class_system()
|
69
|
+
1<2 ? 'lower' : 'middle'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_1
|
74
|
+
assert_equal "classy", "me".class
|
75
|
+
# The main use for this would be to call "original" implementations provided by Kernel or some other base module that you can be pretty sure is an ancestor of self...
|
76
|
+
assert_contains String.ancestors, Kernel
|
77
|
+
assert_equal String, "me".mcall(Kernel, :class)
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_2_after_doing_alias_method_chain
|
81
|
+
String.class_eval do
|
82
|
+
#remove_method :to_s
|
83
|
+
include ClassSystem
|
84
|
+
end
|
85
|
+
assert_equal "lower", "me".class # Version 3
|
86
|
+
assert_equal "classy", "me".class_without_class_system # Version 2
|
87
|
+
assert_equal String, "me".mcall(Kernel, :class) # Version 1
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
=end
|
92
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#--
|
2
|
+
# Author:: Tyler Rick
|
3
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
4
|
+
# License:: Ruby License
|
5
|
+
# Submit to Facets?:: Yes. Actually, Facets already has one, which takes a symbol (:inherited, :local, :public, etc.). Possibly merge with that one. Accept symbol *or* boolean as arg?
|
6
|
+
# Developer notes::
|
7
|
+
#++
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'facets/core/module/alias_method_chain'
|
11
|
+
require 'facets/core/symbol/to_proc'
|
12
|
+
|
13
|
+
class Object
|
14
|
+
|
15
|
+
# Ruby's built-in Object#methods says:
|
16
|
+
# Returns a list of the names of methods publicly accessible in obj. This will include all the methods accessible in obj's ancestors.
|
17
|
+
#
|
18
|
+
# But sometimes you don't _want_ all of obj's ancestors!
|
19
|
+
#
|
20
|
+
# This <tt>Object#methods</tt> adds the following features to the built-in <tt>Object#methods</tt>:
|
21
|
+
# * Provides the same +include_super+ option that Module#instance_methods has (Backwards compatible, because default is +true+)
|
22
|
+
# * Returns an array of symbols rather than strings (Not backwards compatible)
|
23
|
+
# * Sorts the array for you so you don't have to! (Not backwards compatible)
|
24
|
+
def methods_with_sorting_and_include_super(include_super = true)
|
25
|
+
if include_super
|
26
|
+
methods_without_sorting_and_include_super
|
27
|
+
else
|
28
|
+
(methods_without_sorting_and_include_super - Object.methods_without_sorting_and_include_super)
|
29
|
+
end.sort.map(&:to_sym)
|
30
|
+
end
|
31
|
+
alias_method_chain :methods, :sorting_and_include_super
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
# _____ _
|
37
|
+
# |_ _|__ ___| |_
|
38
|
+
# | |/ _ \/ __| __|
|
39
|
+
# | | __/\__ \ |_
|
40
|
+
# |_|\___||___/\__|
|
41
|
+
#
|
42
|
+
=begin test
|
43
|
+
require 'test/unit'
|
44
|
+
|
45
|
+
class TheTest < Test::Unit::TestCase
|
46
|
+
def test_1
|
47
|
+
assert_equal [:[]], Array.methods(false)
|
48
|
+
assert Array.methods.size > Array.methods(false).size
|
49
|
+
|
50
|
+
assert !Object.methods(true).include?(:[])
|
51
|
+
assert Array. methods(true).include?(:[])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
=end
|
55
|
+
|
56
|
+
# Old idea:
|
57
|
+
#
|
58
|
+
# class Object
|
59
|
+
# def own_methods # (or Object#my_methods)
|
60
|
+
# ((methods - Object.methods).sort)
|
61
|
+
# # Could just use self.class.instance_methods(false) but what if we also want class/module methods to be included?
|
62
|
+
# end
|
63
|
+
# end
|