quality_extensions 0.1.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.
Files changed (100) hide show
  1. data/Readme +54 -0
  2. data/lib/qualitysmith_extensions/all.rb +4 -0
  3. data/lib/qualitysmith_extensions/array/all.rb +2 -0
  4. data/lib/qualitysmith_extensions/array/average.rb +44 -0
  5. data/lib/qualitysmith_extensions/array/classify.rb +97 -0
  6. data/lib/qualitysmith_extensions/array/expand_ranges.rb +52 -0
  7. data/lib/qualitysmith_extensions/array/group_by.rb +134 -0
  8. data/lib/qualitysmith_extensions/array/sequence.rb +66 -0
  9. data/lib/qualitysmith_extensions/array/shell_escape.rb +36 -0
  10. data/lib/qualitysmith_extensions/array/to_a_recursive.rb +41 -0
  11. data/lib/qualitysmith_extensions/array/to_query_string.rb +96 -0
  12. data/lib/qualitysmith_extensions/collection_extensions_for_cgi.rb +2 -0
  13. data/lib/qualitysmith_extensions/colored/toggleability.rb +62 -0
  14. data/lib/qualitysmith_extensions/console/command.facets.1.8.51.rb +749 -0
  15. data/lib/qualitysmith_extensions/console/command.facets.1.8.54.rb +748 -0
  16. data/lib/qualitysmith_extensions/console/command.rb +944 -0
  17. data/lib/qualitysmith_extensions/date/all.rb +2 -0
  18. data/lib/qualitysmith_extensions/date/deprecated.rb +40 -0
  19. data/lib/qualitysmith_extensions/date/iso8601.rb +31 -0
  20. data/lib/qualitysmith_extensions/date/month_ranges.rb +122 -0
  21. data/lib/qualitysmith_extensions/dir/each_child.rb +58 -0
  22. data/lib/qualitysmith_extensions/enumerable/enum.rb +69 -0
  23. data/lib/qualitysmith_extensions/enumerable/select_until.rb +4 -0
  24. data/lib/qualitysmith_extensions/enumerable/select_while.rb +109 -0
  25. data/lib/qualitysmith_extensions/exception/inspect_with_backtrace.rb +65 -0
  26. data/lib/qualitysmith_extensions/file/exact_match_regexp.rb +34 -0
  27. data/lib/qualitysmith_extensions/file_test/binary_file.rb +110 -0
  28. data/lib/qualitysmith_extensions/find/select.rb +68 -0
  29. data/lib/qualitysmith_extensions/global_variable_set.rb +153 -0
  30. data/lib/qualitysmith_extensions/hash/all.rb +2 -0
  31. data/lib/qualitysmith_extensions/hash/to_date.rb +34 -0
  32. data/lib/qualitysmith_extensions/hash/to_query_string.rb +121 -0
  33. data/lib/qualitysmith_extensions/kernel/all.rb +2 -0
  34. data/lib/qualitysmith_extensions/kernel/autoreload.rb +128 -0
  35. data/lib/qualitysmith_extensions/kernel/backtrace.rb +71 -0
  36. data/lib/qualitysmith_extensions/kernel/capture_output.rb +115 -0
  37. data/lib/qualitysmith_extensions/kernel/die.rb +49 -0
  38. data/lib/qualitysmith_extensions/kernel/example_printer.rb +81 -0
  39. data/lib/qualitysmith_extensions/kernel/filter_output.rb +108 -0
  40. data/lib/qualitysmith_extensions/kernel/remove_const.rb +178 -0
  41. data/lib/qualitysmith_extensions/kernel/remove_module.rb +127 -0
  42. data/lib/qualitysmith_extensions/kernel/require_all.rb +186 -0
  43. data/lib/qualitysmith_extensions/kernel/require_local_all.rb +4 -0
  44. data/lib/qualitysmith_extensions/kernel/require_once.rb +18 -0
  45. data/lib/qualitysmith_extensions/kernel/simulate_input.rb +52 -0
  46. data/lib/qualitysmith_extensions/kernel/trap_chain.rb +61 -0
  47. data/lib/qualitysmith_extensions/kernel/windows_platform.rb +46 -0
  48. data/lib/qualitysmith_extensions/module/alias_method.rb +6 -0
  49. data/lib/qualitysmith_extensions/module/alias_method_chain.rb +165 -0
  50. data/lib/qualitysmith_extensions/module/ancestry_of_instance_method.rb +43 -0
  51. data/lib/qualitysmith_extensions/module/attribute_accessors.rb +49 -0
  52. data/lib/qualitysmith_extensions/module/basename.rb +76 -0
  53. data/lib/qualitysmith_extensions/module/bool_attr_accessor.rb +497 -0
  54. data/lib/qualitysmith_extensions/module/class_methods.rb +87 -0
  55. data/lib/qualitysmith_extensions/module/create.rb +315 -0
  56. data/lib/qualitysmith_extensions/module/create_setter.rb +9 -0
  57. data/lib/qualitysmith_extensions/module/dirname.rb +4 -0
  58. data/lib/qualitysmith_extensions/module/guard_method.rb +312 -0
  59. data/lib/qualitysmith_extensions/module/includable_once.rb +10 -0
  60. data/lib/qualitysmith_extensions/module/join.rb +66 -0
  61. data/lib/qualitysmith_extensions/module/malias_method_chain.rb +92 -0
  62. data/lib/qualitysmith_extensions/module/module_methods.rb +4 -0
  63. data/lib/qualitysmith_extensions/module/namespace.rb +112 -0
  64. data/lib/qualitysmith_extensions/module/parents.rb +61 -0
  65. data/lib/qualitysmith_extensions/module/remove_const.rb +117 -0
  66. data/lib/qualitysmith_extensions/module/split.rb +55 -0
  67. data/lib/qualitysmith_extensions/month.rb +66 -0
  68. data/lib/qualitysmith_extensions/mutex/if_available.rb +75 -0
  69. data/lib/qualitysmith_extensions/object/ancestry_of_method.rb +257 -0
  70. data/lib/qualitysmith_extensions/object/default.rb +69 -0
  71. data/lib/qualitysmith_extensions/object/if_else.rb +157 -0
  72. data/lib/qualitysmith_extensions/object/ignore_access.rb +84 -0
  73. data/lib/qualitysmith_extensions/object/mcall.rb +92 -0
  74. data/lib/qualitysmith_extensions/object/methods.rb +63 -0
  75. data/lib/qualitysmith_extensions/object/send_if.rb +151 -0
  76. data/lib/qualitysmith_extensions/object/send_if_not_nil.rb +35 -0
  77. data/lib/qualitysmith_extensions/object/singleton_send.rb +129 -0
  78. data/lib/qualitysmith_extensions/regexp/join.rb +111 -0
  79. data/lib/qualitysmith_extensions/string/all.rb +2 -0
  80. data/lib/qualitysmith_extensions/string/constantize.rb +4 -0
  81. data/lib/qualitysmith_extensions/string/digits_only.rb +27 -0
  82. data/lib/qualitysmith_extensions/string/each_char_with_index.rb +41 -0
  83. data/lib/qualitysmith_extensions/string/md5.rb +29 -0
  84. data/lib/qualitysmith_extensions/string/shell_escape.rb +43 -0
  85. data/lib/qualitysmith_extensions/string/to_underscored_label.rb +37 -0
  86. data/lib/qualitysmith_extensions/string/with_knowledge_of_color.rb +64 -0
  87. data/lib/qualitysmith_extensions/symbol/constantize.rb +69 -0
  88. data/lib/qualitysmith_extensions/symbol/match.rb +157 -0
  89. data/lib/qualitysmith_extensions/template.rb +33 -0
  90. data/lib/qualitysmith_extensions/test/all.rb +2 -0
  91. data/lib/qualitysmith_extensions/test/assert_anything.rb +93 -0
  92. data/lib/qualitysmith_extensions/test/assert_changed.rb +66 -0
  93. data/lib/qualitysmith_extensions/test/assert_exception.rb +66 -0
  94. data/lib/qualitysmith_extensions/test/assert_includes.rb +36 -0
  95. data/lib/qualitysmith_extensions/test/assert_user_error.rb +37 -0
  96. data/lib/qualitysmith_extensions/test/difference_highlighting.rb +323 -0
  97. data/lib/qualitysmith_extensions/time/all.rb +2 -0
  98. data/lib/qualitysmith_extensions/time/deprecated.rb +31 -0
  99. data/test/all.rb +16 -0
  100. metadata +148 -0
@@ -0,0 +1,186 @@
1
+ #--
2
+ # Author:: Tyler Rick
3
+ # Copyright:: Copyright (c) 2007 QualitySmith, Inc.
4
+ # License:: Ruby License
5
+ # Submit to Facets?:: Yes
6
+ #++
7
+
8
+ require 'rubygems'
9
+ require 'facets/more/filelist'
10
+
11
+ require 'facets/core/kernel/require_local'
12
+ require_local '../file/exact_match_regexp'
13
+
14
+ module Kernel
15
+
16
+ # <tt>require</tt>s all Ruby files specified by <tt>what</tt>, but not matching any of the exclude filters.
17
+ # * If <tt>what</tt> is a string, recursively <tt>require</tt>s all Ruby files in the directory named <tt>what</tt> or any of its subdirectories.
18
+ # * If <tt>what</tt> is a FileList, <tt>require</tt>s all Ruby files that match the <tt>what</tt> FileList.
19
+ #
20
+ # Options:
21
+ # <tt>:exclude</tt>: An array of regular expressions or glob patterns that will be passed to FileList#exclude. If you specify this option, a file will not be included if it matches *any* of these patterns.
22
+ # <tt>:exclude_files</tt>: An array of filenames to exclude. These will be matched exactly, so if you tell it to exclude 'bar.rb', 'foobar.rb' will _not_ be excluded.
23
+ #
24
+ # Examples:
25
+ # require_all 'lib/', :exclude => [/ignore/, /bogus/] # will require 'lib/a.rb', 'lib/long/path/b.rb', but not 'lib/ignore/c.rb'
26
+ # require_all File.dirname(__FILE__), :exclude_files => ['blow_up_stuff.rb']
27
+ def require_all(what, options = {})
28
+ files, exclusions = [nil]*2
29
+
30
+ case what
31
+ when String
32
+ base_dir = what
33
+ base_dir += '/' unless base_dir[-1].chr == '/'
34
+ files = FileList[base_dir + "**/*.rb"]
35
+ when FileList
36
+ files = what
37
+ else
38
+ raise ArgumentError.new("Expected a String or a FileList")
39
+ end
40
+ files = files.exclude(*exclusions) if (exclusions = options.delete(:exclude))
41
+ files = files.exclude(*exclusions.map {|a| File.exact_match_regexp(a) }) if (exclusions = options.delete(:exclude_files))
42
+
43
+ files.each do |filename|
44
+ # puts "requiring #{filename}" if filename =~ /test/
45
+ require filename
46
+ end
47
+ end
48
+
49
+ # <tt>require</tt>s all Ruby files in +dir+ (relative to <tt>File.dirname(__FILE__)</tt>) or any of its subdirectories.
50
+ #
51
+ # This is just a shortcut for this:
52
+ # require_all File.join(File.dirname(__FILE__), dir)
53
+ #
54
+ # All of the +options+ available for +require_all+ are still available here.
55
+ #
56
+ def require_local_all(dir = './', options = {})
57
+ raise ArgumentError.new("dir must be a String") unless dir.is_a?(String)
58
+ local_dir = File.dirname( caller[0] )
59
+ require_all(
60
+ File.join(local_dir, dir),
61
+ options
62
+ )
63
+ end
64
+
65
+ end
66
+
67
+ # _____ _
68
+ # |_ _|__ ___| |_
69
+ # | |/ _ \/ __| __|
70
+ # | | __/\__ \ |_
71
+ # |_|\___||___/\__|
72
+ #
73
+ =begin test
74
+ require 'tmpdir'
75
+ require 'fileutils'
76
+ require 'English'
77
+
78
+ class TheTest < Test::Unit::TestCase
79
+ def setup
80
+ @base_dir = "#{Dir.tmpdir}/require_all_test"
81
+ @base_local_dir = File.dirname(__FILE__) # To allow testing of require_local_all. But tests should put everything in "#{@base_local_dir}/require_all_test" to avoid clutter or name conflicts with other files!
82
+ FileUtils.mkdir @base_dir
83
+ @deep_dir = "really/really/deep/subdir"
84
+ $loaded = []
85
+
86
+ end
87
+ def teardown
88
+ FileUtils.rm_rf @base_dir
89
+ FileUtils.rm_rf "#{@base_local_dir}/require_all_test"
90
+ end
91
+
92
+
93
+ def test_repeat_requires
94
+ create_ruby_file 'moo.rb'
95
+
96
+ require_all File.dirname(@base_dir)
97
+ assert_equal ['moo.rb'], $loaded
98
+
99
+ require "#{@base_dir}/moo.rb"
100
+ assert_equal ['moo.rb'], $loaded
101
+
102
+ # Good! It refuses to load it again, even if we drop the ".rb" part!
103
+ require "#{@base_dir}/moo"
104
+ assert_equal ['moo.rb'], $loaded
105
+
106
+ # But, we can still trick it!
107
+ $LOAD_PATH << @base_dir
108
+ require "moo"
109
+ assert_equal ['moo.rb', 'moo.rb'], $loaded
110
+
111
+ load "moo.rb"
112
+ assert_equal ['moo.rb', 'moo.rb', 'moo.rb'], $loaded
113
+ end
114
+
115
+ def test_deep_subdir
116
+ create_ruby_file 'flip.rb'
117
+ create_ruby_file @deep_dir + "/flop.rb"
118
+
119
+ require_all File.dirname(@base_dir)
120
+ assert_equal ['flip.rb', @deep_dir + "/flop.rb"], $loaded
121
+ end
122
+
123
+ def test_exclude_pattern
124
+ create_ruby_file 'require_me.rb'
125
+ create_ruby_file 'please_ignore_me.rb'
126
+
127
+ require_all File.dirname(@base_dir), :exclude => [/ignore/]
128
+ assert_equal ['require_me.rb'], $loaded
129
+ end
130
+
131
+ def test_require_local_all
132
+ create_ruby_file 'require_all_test/lib/require_me.rb', @base_local_dir
133
+ create_ruby_file 'require_all_test/lib/please_ignore_me.rb', @base_local_dir
134
+
135
+ require_local_all 'require_all_test/lib', :exclude => [/ignore/]
136
+ assert_equal ['require_all_test/lib/require_me.rb'], $loaded
137
+ end
138
+
139
+ def test_exclude_pattern_with_directory
140
+ create_ruby_file 'subdir/test/assert_even.rb'
141
+ create_ruby_file 'subdir/test/assert_odd.rb'
142
+
143
+ require_all File.dirname(@base_dir), :exclude => [/(^|\/)test/]
144
+ assert_equal [], $loaded
145
+ end
146
+
147
+ def test_passing_a_FileList
148
+ create_ruby_file 'subdir/junk/pretty_much_useless.rb'
149
+ create_ruby_file 'subdir/not_junk/good_stuff.rb'
150
+
151
+ require_all FileList[File.dirname(@base_dir) + "/**/*.rb"], :exclude => [/(^|\/)junk/]
152
+ assert_equal ['subdir/not_junk/good_stuff.rb'], $loaded
153
+ end
154
+
155
+ def test_exclude_filename
156
+ create_ruby_file 'yes.rb'
157
+ create_ruby_file 'all.rb'
158
+
159
+ # :todo: Interesting how none of these patterns work. I would have expected them to. Is there a bug in FileList? Find out...
160
+ # /usr/lib/ruby/gems/1.8/gems/facets-1.8.51/lib/facets/more/filelist.rb
161
+ #require_all File.dirname(@base_dir), :exclude => ['all.rb']
162
+ #require_all File.dirname(@base_dir), :exclude => ['**/all']
163
+ #require_all File.dirname(@base_dir), :exclude => [/^all\.rb$/]
164
+ # This works, but it's too much to expect users to type out!:
165
+ #require_all File.dirname(@base_dir), :exclude => [/(\/|^)all\.rb$/]
166
+
167
+ # So...... I added an :exclude_files option so that people wouldn't have to!
168
+ require_all File.dirname(@base_dir), :exclude_files => ['all.rb']
169
+
170
+ assert_equal ['yes.rb'], $loaded
171
+ end
172
+
173
+ #-------------------------------------------------------------------------------------------------------------------------------
174
+ # Helpers
175
+
176
+ def create_ruby_file(file_name, base_dir = @base_dir)
177
+ # use dirname instead?
178
+ if file_name =~ /(.*)\//
179
+ FileUtils.mkdir_p base_dir + '/' + $1
180
+ end
181
+ path = base_dir + '/' + file_name
182
+ File.open(path, "w") {|f| f.puts "$loaded << '#{file_name}'"}
183
+ end
184
+
185
+ end
186
+ =end
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ # Alias for:
3
+ require 'qualitysmith_extensions/kernel/require_all'
4
+
@@ -0,0 +1,18 @@
1
+ #--
2
+ # Author:: Tyler Rick
3
+ # Copyright:: Copyright (c) 2007 QualitySmith, Inc.
4
+ # License:: Ruby License
5
+ # Submit to Facets?:: No, not yet
6
+ #++
7
+
8
+ require 'rubygems'
9
+
10
+ module Kernel
11
+ # Fixes bug in Ruby (1.8, at least -- not sure if 2.0 fixes it) where a file can be required twice if the path is spelled differently.
12
+ def require_once(name)
13
+ raise NotImplementedError
14
+ # store expand_path(name) in an array ($required_files or something)
15
+ # only do the require if it wasn't already in the array
16
+ end
17
+ end
18
+
@@ -0,0 +1,52 @@
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
+ #++
8
+
9
+ require 'stringio'
10
+ require 'rubygems'
11
+
12
+ # Simulates a user typing in +input_string+ on the keyboard.
13
+ #
14
+ # Useful for testing console apps that are ordinarily (they prompt the user for input).
15
+ #
16
+ # output = simulate_inpute('foo') do
17
+ # input = $stdin.gets
18
+ # capture_output { do_stuff() }
19
+ # end
20
+ #
21
+ def simulate_input(input_string, &block)
22
+
23
+ original_stdin = $stdin
24
+ $stdin = StringIO.new(input_string, 'r')
25
+
26
+ begin
27
+ yield
28
+ rescue Exception
29
+ raise
30
+ ensure
31
+ $stdin = original_stdin
32
+ end
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
+ input_received = nil
48
+ simulate_input('foo') { input_received = $stdin.getc.chr }
49
+ assert_equal 'f', input_received
50
+ end
51
+ end
52
+ =end
@@ -0,0 +1,61 @@
1
+ #--
2
+ # Author:: Tyler Rick
3
+ # Copyright:: Copyright (c) 2007 QualitySmith, Inc.
4
+ # License:: Ruby License
5
+ # Submit to Facets?:: Yes!
6
+ #++
7
+
8
+ module Kernel
9
+ # Calling <tt>Kernel#trap()</tt> by itself will _replace_ any previously registered handler code.
10
+ # <tt>Kernel#trap_chain()</tt>, on the other hand, will _add_ the block you supply to the existing "list" of registered handler blocks.
11
+ # Similar to the way <tt>Kernel#at_exit()</tt> works, <tt>Kernel#trap_chain()</tt> will _prepend_ the given +block+ to the call chain for the given +signal_name+.
12
+ # When the signal occurs, your block will be executed first and then the previously registered handler will be invoked. This can be called repeatedly to create a "chain" of handlers.
13
+ def trap_chain(signal_name, *args, &block)
14
+ previous_interrupt_handler = trap(signal_name, *args) {}
15
+ trap(signal_name, *args) do
16
+ block.call
17
+ previous_interrupt_handler.call unless previous_interrupt_handler == "DEFAULT"
18
+ end
19
+ end
20
+ end
21
+
22
+ # _____ _
23
+ # |_ _|__ ___| |_
24
+ # | |/ _ \/ __| __|
25
+ # | | __/\__ \ |_
26
+ # |_|\___||___/\__|
27
+ #
28
+ =begin test
29
+ require 'rubygems'
30
+ require 'qualitysmith_extensions/kernel/capture_output'
31
+ require 'fileutils'
32
+
33
+ class TheTest < Test::Unit::TestCase
34
+ def setup
35
+ FileUtils.touch('trap_chain_test_output')
36
+ end
37
+ def teardown
38
+ FileUtils.remove_entry_secure 'trap_chain_test_output'
39
+ end
40
+
41
+ def test_1
42
+ output = capture_output do # For some reason, this wasn't capturing the output from the child process when I did plain puts, so I changed it to write to a file instead...
43
+
44
+ pid = fork do
45
+ trap_chain("INT") { File.open('trap_chain_test_output', 'a') {|file| file.puts "Handler 1" } }
46
+ trap_chain("INT") { File.open('trap_chain_test_output', 'a') {|file| file.puts "Handler 2"; file.puts "Exiting..."; }; exit }
47
+ trap_chain("INT") { File.open('trap_chain_test_output', 'a') {|file| file.puts "Handler 3" } }
48
+ puts 'Hello world'
49
+ sleep 5
50
+ end
51
+ Process.kill "INT", pid
52
+ Process.wait
53
+
54
+ end
55
+
56
+ assert_equal "Handler 3\nHandler 2\nExiting...\n", File.read('trap_chain_test_output')
57
+ end
58
+
59
+ end
60
+ =end
61
+
@@ -0,0 +1,46 @@
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
+ # Changes::
8
+ #++
9
+
10
+
11
+ module Kernel
12
+ def windows_platform?
13
+ RUBY_PLATFORM =~ /mswin32/
14
+
15
+ # What about mingw32 or cygwin32?
16
+ #RUBY_PLATFORM =~ /(win|w)32$/
17
+
18
+ # What about 64-bit Windows?
19
+ end
20
+ end
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+ # _____ _
29
+ # |_ _|__ ___| |_
30
+ # | |/ _ \/ __| __|
31
+ # | | __/\__ \ |_
32
+ # |_|\___||___/\__|
33
+ #
34
+ =begin test
35
+ require 'test/unit'
36
+
37
+ class TheTest < Test::Unit::TestCase
38
+ def test_1
39
+ # Impossible to test, unless your platform is Windows.
40
+ assert true
41
+ end
42
+
43
+ end
44
+ =end
45
+
46
+
@@ -0,0 +1,6 @@
1
+ # Idea:
2
+ # Allow using hashes:
3
+ # alias_method :code_review => :view_commits
4
+ # instead of
5
+ # alias_method :code_review, :view_commits
6
+ # because I always forget which argument becomes the argument for which
@@ -0,0 +1,165 @@
1
+ #--
2
+ # Author:: Tyler Rick
3
+ # Copyright:: Copyright (c) 2007 the Rails people; QualitySmith, Inc.
4
+ # License:: Ruby License
5
+ # Submit to Facets?:: Yes.
6
+ # Developer notes::
7
+ # Changes::
8
+ #++
9
+
10
+ require 'rubygems'
11
+ gem 'facets'
12
+ #require 'facets/core/module/alias_method_chain' # Doesn't support blocks or I'd use it.
13
+ require 'facets/core/kernel/singleton_class'
14
+
15
+
16
+ # /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/core_ext/module/aliasing.rb
17
+ class Module
18
+ def alias_method_chain(target, feature)
19
+ # Strip out punctuation on predicates or bang methods since
20
+ # e.g. target?_without_feature is not a valid method name.
21
+ aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
22
+ yield(aliased_target, punctuation) if block_given?
23
+ alias_method "#{aliased_target}_without_#{feature}#{punctuation}", target
24
+ alias_method target, "#{aliased_target}_with_#{feature}#{punctuation}"
25
+ end
26
+ end
27
+ # end /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/core_ext/module/aliasing.rb
28
+
29
+ class Module
30
+
31
+ def alias_method_chain_with_prevent_repeat_aliasing(target, feature, &block)
32
+ # Strip out punctuation on predicates or bang methods since
33
+ # e.g. target?_without_feature is not a valid method name.
34
+
35
+ aliased_target, punctuation = target.to_s.sub(/([?!])$/, ''), $1
36
+ target_without_feature = "#{aliased_target}_without_#{feature}#{punctuation}"
37
+
38
+ #puts "#{target} is #{method_defined?(target)}"
39
+ alias_method_chain_without_prevent_repeat_aliasing(target, feature, &block) unless method_defined?(target_without_feature)
40
+ end
41
+ alias_method_chain :alias_method_chain, :prevent_repeat_aliasing
42
+
43
+ # If you pass <tt>:create_target => true</tt> as one of the +options+:
44
+ # * Guarantees that <tt>alias_method_chain target, feature</tt> will work even if the target method has not been defined yet.
45
+ # If the target method doesn't exist yet, an empty (no-op) target method will be created.
46
+ # * This could come in handy for callback methods (method_added, method_missing, etc.), for instane, when you don't know if that
47
+ # particular callback method has been defined or not.
48
+ # * You want your alias_method_chain to wrap the existing method if there *is* an existing method, but to <b>not break</b> in
49
+ # the case that the method _doesn't_ exist.
50
+ def alias_method_chain_with_target_need_not_exist(target, feature, options = {}, &block)
51
+ create_target = options.delete(:create_target)
52
+
53
+ if create_target && true #!self.methods.include?(target)
54
+ self.send :define_method, target do |*args|
55
+ # Intentionally empty
56
+ end
57
+ end
58
+
59
+ alias_method_chain_without_target_need_not_exist(target, feature, &block)
60
+ end
61
+ alias_method_chain :alias_method_chain, :target_need_not_exist
62
+ end
63
+
64
+
65
+
66
+ =begin test
67
+ require 'test/unit'
68
+
69
+ class Test_alias_method_chain_basic < Test::Unit::TestCase
70
+
71
+ class X
72
+ def foo?
73
+ 'foo?'
74
+ end
75
+ def foo_with_feature?
76
+ foo_without_feature? + '_with_feature'
77
+ end
78
+ end
79
+
80
+ def test_question_mark
81
+ name, punctuation = nil, nil
82
+ X.instance_eval do
83
+ alias_method_chain :foo?, :feature do |a, b|
84
+ name, punctuation = a, b
85
+ end
86
+ end
87
+
88
+ assert_equal 'foo?_with_feature', X.new.foo?
89
+ assert_equal 'foo', name
90
+ assert_equal '?', punctuation
91
+ end
92
+
93
+ class Y
94
+ def foo!
95
+ 'foo!'
96
+ end
97
+ def foo_with_feature!
98
+ foo_without_feature! + '_with_feature'
99
+ end
100
+ end
101
+
102
+ def test_exclamation_mark
103
+ name, punctuation = nil, nil
104
+ Y.instance_eval do
105
+ alias_method_chain :foo!, :feature do |a, b|
106
+ name, punctuation = a, b
107
+ end
108
+ end
109
+
110
+ assert_equal 'foo!_with_feature', Y.new.foo!
111
+ assert_equal 'foo', name
112
+ assert_equal '!', punctuation
113
+ end
114
+
115
+ end
116
+
117
+ class Test_alias_method_chain_with_prevent_repeat_aliasing < Test::Unit::TestCase
118
+
119
+ class X
120
+ def foo
121
+ 'foo'
122
+ end
123
+ def foo_with_feature
124
+ foo_without_feature + '_with_feature'
125
+ end
126
+ alias_method_chain :foo, :feature
127
+ alias_method_chain :foo, :feature # We want to test that this won't cause an infinite recursion (stack overflow).
128
+ end
129
+
130
+ def test_1
131
+ assert_equal 'foo_with_feature', X.new.foo
132
+ end
133
+
134
+ end
135
+
136
+
137
+ class Test_alias_method_chain_with_target_need_not_exist < Test::Unit::TestCase
138
+
139
+ # Let's assume that we are *re*-opening X here, and at this point we *don't know* if it has a foo method or not.
140
+ # Also, we *don't want to care*. We just want to add to the chain if the method exists, or *create* the chain
141
+ # if it does not yet.
142
+ class X
143
+ def foo_with_feature
144
+ # *Don't* do this if you're using :create_target => true:
145
+ # foo_without_feature + '_with_feature'
146
+ # If you're using :create_target => true, then you are pretty much saying "I don't know anything about thhe target method".
147
+ # Yet the previous statement shows that you expect it to return a String. You can't do that. You can't pretend to know
148
+ # anything about it's return value. It will always be nil if alias_method_chain created an empty method for you.
149
+ # But, it may be something else if it already existed and alias_method_chain did *not* create an empty method for you.
150
+
151
+ # The safest thing to do is to just call it and pay not attention to its return value. (Or at least *consider* the
152
+ # possibility that it may be nil.)
153
+
154
+ foo_without_feature
155
+ 'feature was successfully added'
156
+ end
157
+ alias_method_chain :foo, :feature, :create_target => true
158
+ end
159
+
160
+ def test_1
161
+ assert_equal 'feature was successfully added', X.new.foo
162
+ assert_equal 'feature was successfully added', X.new.foo { 'test that it works with a block' }
163
+ end
164
+ end
165
+ =end