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.
- 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,151 @@
|
|
|
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
|
+
# * The name of this method maybe ought to be a little more specific. What does anyone else think?
|
|
8
|
+
# * It should say something about the fact that it the message sending is conditional but the block execution is unconditional.
|
|
9
|
+
# * always_execute_block_but_only_send_message_if ? Hmm... a bit too verbose, perhaps.
|
|
10
|
+
# * conditional_passthrough ?
|
|
11
|
+
# * passthrough_unless ?
|
|
12
|
+
# * use_wrapper_method_if ?
|
|
13
|
+
# * Or just leave it how it is because all the alternatives are too long...
|
|
14
|
+
#++
|
|
15
|
+
|
|
16
|
+
require 'rubygems'
|
|
17
|
+
gem 'facets'
|
|
18
|
+
require 'facets/core/kernel/with' # returning
|
|
19
|
+
|
|
20
|
+
class Object
|
|
21
|
+
# Sends +message+ to +self+ (including +block_to_always_execute+ if supplied) if +condition+ is met. If +condition+ is _not_ met,
|
|
22
|
+
# +block_to_always_execute+ will still be called (if supplied), but we will _not_ pass the message. (If +condition+ is not met
|
|
23
|
+
# and +block_to_always_execute+ is not supplied, it will simply return +self+.)
|
|
24
|
+
#
|
|
25
|
+
# In summary:
|
|
26
|
+
# * +block+: _always_ executed
|
|
27
|
+
# * +message+: only sent if +condition+
|
|
28
|
+
#
|
|
29
|
+
# If a block (+block_to_always_execute+) is supplied, it is passed on to the message if the condition is met; (otherwise it is
|
|
30
|
+
# simply called without sending the message).
|
|
31
|
+
#
|
|
32
|
+
# This is useful if you want to wrap a block with some method but you only want the method itself to be used some of the time.
|
|
33
|
+
# For example, if it's for benchmarking, you may only want to enable it during development but disable during production to save on some overhead.
|
|
34
|
+
#
|
|
35
|
+
# Note: this cannot be used to call methods that expect blocks (Ruby 1.9 maybe?)
|
|
36
|
+
#
|
|
37
|
+
def send_if(condition, message, *args, &block_to_always_execute)
|
|
38
|
+
if condition
|
|
39
|
+
self.__send__(message, *args, &block_to_always_execute)
|
|
40
|
+
else
|
|
41
|
+
if block_given?
|
|
42
|
+
block_to_always_execute.call
|
|
43
|
+
else
|
|
44
|
+
self
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Opposite of send_if
|
|
50
|
+
def send_unless(condition, *args, &block)
|
|
51
|
+
self.send_if(!condition, *args, &block)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Lets you reduce duplication a little bit. Can do this:
|
|
55
|
+
# @foo.send_if_true(color)
|
|
56
|
+
# instead of this:
|
|
57
|
+
# @foo.send_if(color, color)
|
|
58
|
+
#
|
|
59
|
+
def send_if_true(condition, *args, &block)
|
|
60
|
+
self.send_if(condition, condition, *args, &block)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# _____ _
|
|
71
|
+
# |_ _|__ ___| |_
|
|
72
|
+
# | |/ _ \/ __| __|
|
|
73
|
+
# | | __/\__ \ |_
|
|
74
|
+
# |_|\___||___/\__|
|
|
75
|
+
#
|
|
76
|
+
=begin test
|
|
77
|
+
require 'test/unit'
|
|
78
|
+
|
|
79
|
+
class Foo
|
|
80
|
+
attr_reader :called_benchmark
|
|
81
|
+
def benchmark(&block)
|
|
82
|
+
@called_benchmark = true
|
|
83
|
+
yield
|
|
84
|
+
sleep 0.1 # Simulate lots of overhead, which we may want to avoid if we can help it
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
class String
|
|
88
|
+
def pink
|
|
89
|
+
"#{self} (in pink)"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
class TheTest < Test::Unit::TestCase
|
|
94
|
+
def setup
|
|
95
|
+
@foo = Foo.new
|
|
96
|
+
@string = 'food'
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def test_send_if_with_true_condition
|
|
100
|
+
executed_block = false
|
|
101
|
+
@foo.send_if(true, :benchmark) do
|
|
102
|
+
executed_block = true
|
|
103
|
+
end
|
|
104
|
+
assert executed_block
|
|
105
|
+
assert @foo.called_benchmark
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def test_send_if_with_false_condition
|
|
109
|
+
executed_block = false
|
|
110
|
+
@foo.send_if(false, :benchmark) do
|
|
111
|
+
executed_block = true
|
|
112
|
+
end
|
|
113
|
+
assert executed_block
|
|
114
|
+
assert !@foo.called_benchmark
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def test_send_if_with_no_block
|
|
118
|
+
color = nil
|
|
119
|
+
returned = @string.send_if(color, color)
|
|
120
|
+
assert_equal 'food', @string
|
|
121
|
+
assert_equal @string, returned
|
|
122
|
+
|
|
123
|
+
color = :pink
|
|
124
|
+
returned = @string.send_if(color, color)
|
|
125
|
+
assert_equal 'food', @string # @string itself should be unchanged, but the return value should be be a modified form of @string
|
|
126
|
+
assert_equal "#{@string} (in pink)", returned
|
|
127
|
+
end
|
|
128
|
+
def test_send_if_true_with_no_block
|
|
129
|
+
color = nil
|
|
130
|
+
returned = @string.send_if_true(color)
|
|
131
|
+
assert_equal 'food', @string
|
|
132
|
+
assert_equal @string, returned
|
|
133
|
+
|
|
134
|
+
color = :pink
|
|
135
|
+
returned = @string.send_if_true(color)
|
|
136
|
+
assert_equal 'food', @string
|
|
137
|
+
assert_equal "#{@string} (in pink)", returned
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_send_unless
|
|
141
|
+
executed_block = false
|
|
142
|
+
@foo.send_unless(false, :benchmark) do
|
|
143
|
+
executed_block = true
|
|
144
|
+
end
|
|
145
|
+
assert executed_block
|
|
146
|
+
assert @foo.called_benchmark
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
end
|
|
150
|
+
=end
|
|
151
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
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
|
+
def send_if_not_nil(message, *args)
|
|
11
|
+
if message
|
|
12
|
+
send(message, *args)
|
|
13
|
+
else
|
|
14
|
+
self
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# _____ _
|
|
21
|
+
# |_ _|__ ___| |_
|
|
22
|
+
# | |/ _ \/ __| __|
|
|
23
|
+
# | | __/\__ \ |_
|
|
24
|
+
# |_|\___||___/\__|
|
|
25
|
+
#
|
|
26
|
+
=begin test
|
|
27
|
+
require 'test/unit'
|
|
28
|
+
|
|
29
|
+
class TheTest < Test::Unit::TestCase
|
|
30
|
+
def test_1
|
|
31
|
+
assert_equal 'a', 'a'.send_if_not_nil(nil)
|
|
32
|
+
assert_equal 'A', 'a'.send_if_not_nil(:upcase)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
=end
|
|
@@ -0,0 +1,129 @@
|
|
|
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
|
+
# * Method name too long? Imagine if we wanted to string multiple calls together.
|
|
8
|
+
# * Ideas:
|
|
9
|
+
# * single_send
|
|
10
|
+
# * singleton_send
|
|
11
|
+
# * singleton_call
|
|
12
|
+
# * singleton
|
|
13
|
+
# * singsend
|
|
14
|
+
# * extend_send
|
|
15
|
+
# * extend_call
|
|
16
|
+
# * create_and_send
|
|
17
|
+
# * create_and_call
|
|
18
|
+
#++
|
|
19
|
+
|
|
20
|
+
class Object
|
|
21
|
+
|
|
22
|
+
# Creates a singleton method and then calls it.
|
|
23
|
+
#
|
|
24
|
+
# More specificaly, it <tt>extend</tt>s +self+ with the methods from +moduule+ and then sends the supplied +message+ and +args+ (if any).
|
|
25
|
+
#
|
|
26
|
+
# Examples:
|
|
27
|
+
# "whatever".ss(MyColorizer, :colorize, :blue)
|
|
28
|
+
#
|
|
29
|
+
# Advantages:
|
|
30
|
+
# * Keeps things object-oriented. Better than having global/class methods.
|
|
31
|
+
# * (<tt>"whatever".ss(MyColorizer, :colorize).ss(SomeOtherClass, :another_class_method)</tt> instead of
|
|
32
|
+
# * <tt>SomeOtherClass::another_class_method(MyColorizer::colorize("whatever"))</tt>)
|
|
33
|
+
# * Method calls are _listed_ in the order in which they are _called_.
|
|
34
|
+
# * Still lets you keep your methods in a namespace.
|
|
35
|
+
# * Doesn't clutter up the base classes with methods that are only useful within a very small context. The methods are only added to the objects you specify. So you can "use" the base class <b>without cluttering up _all_ instances of the class with your methods</b>.
|
|
36
|
+
# * Useful for cases where creating a subclass wouldn't help because the methods you are calling would still return instances of the base class.
|
|
37
|
+
#
|
|
38
|
+
# Disadvantages:
|
|
39
|
+
# * You have to have/create a *module* for the functions you want to use.
|
|
40
|
+
# * Can't just call .sigleton_send(self, :some_method) if you want to use +some_method+ that's defined in +self+.
|
|
41
|
+
# * So what do we call the module containing the "singleton method"? String::MyColorizer? MyColorizer::String? MyStringColorizer?
|
|
42
|
+
#
|
|
43
|
+
# Adding methods to the base class using Facets' own *namespacing* facilities (Module#namespace and Module#include_as)
|
|
44
|
+
# might actually be a more sensible alternative a lot of the time than bothering to create singleton methods for single objects!
|
|
45
|
+
# That would look somethig like:
|
|
46
|
+
#
|
|
47
|
+
# class String
|
|
48
|
+
# namespace :my_colorizer do
|
|
49
|
+
# def colorize(...); ...; end
|
|
50
|
+
# end
|
|
51
|
+
# end
|
|
52
|
+
# "whatever".my_colorizer.colorize(:blue)
|
|
53
|
+
#
|
|
54
|
+
# or
|
|
55
|
+
#
|
|
56
|
+
# class String
|
|
57
|
+
# include_as :my_colorizer => MyColorizer
|
|
58
|
+
# end
|
|
59
|
+
# "whatever".my_colorizer.colorize(:blue)
|
|
60
|
+
#
|
|
61
|
+
def singleton_send(moduule, message, *args, &block)
|
|
62
|
+
self.extend(moduule)
|
|
63
|
+
self.send(message, *args, &block)
|
|
64
|
+
end
|
|
65
|
+
alias_method :ss, :singleton_send
|
|
66
|
+
|
|
67
|
+
# Couldn't get this idea to work:
|
|
68
|
+
# def singleton_that_accepts_object(object, method_name, *args)
|
|
69
|
+
## #class << self
|
|
70
|
+
## #self.instance_eval do
|
|
71
|
+
## self.class.module_eval do
|
|
72
|
+
## define_method(:colorize2, object.class.instance_method(:colorize2))
|
|
73
|
+
## end
|
|
74
|
+
## # raises "TypeError: bind argument must be an instance of TheTest"
|
|
75
|
+
#
|
|
76
|
+
## object.class.instance_method(method_name).
|
|
77
|
+
## bind(self)
|
|
78
|
+
## # raises "TypeError: bind argument must be an instance of TheTest"
|
|
79
|
+
#
|
|
80
|
+
## self.class.extend(object.class)
|
|
81
|
+
## self.class.send(:include, object.class)
|
|
82
|
+
## # raises "TypeError: wrong argument type Class (expected Module)"
|
|
83
|
+
# self.send(method_name, *args)
|
|
84
|
+
# end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# _____ _
|
|
89
|
+
# |_ _|__ ___| |_
|
|
90
|
+
# | |/ _ \/ __| __|
|
|
91
|
+
# | | __/\__ \ |_
|
|
92
|
+
# |_|\___||___/\__|
|
|
93
|
+
#
|
|
94
|
+
=begin test
|
|
95
|
+
require 'test/unit'
|
|
96
|
+
require 'rubygems'
|
|
97
|
+
require 'qualitysmith_extensions/test/assert_exception'
|
|
98
|
+
require 'qualitysmith_extensions/test/assert_includes'
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
module MyColorizer
|
|
102
|
+
def colorize(color = nil)
|
|
103
|
+
self + " (colorized in #{color})"
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
#module PresentationLayer
|
|
108
|
+
# create_module_method :to_currency do
|
|
109
|
+
# #...
|
|
110
|
+
# end
|
|
111
|
+
#end
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class TheTest1_UsingSingletonSend < Test::Unit::TestCase
|
|
115
|
+
def test_using_singleton_send
|
|
116
|
+
assert_equal "whatever (colorized in )", "whatever".ss(MyColorizer, :colorize)
|
|
117
|
+
assert_equal "whatever (colorized in blue)", "whatever".ss(MyColorizer, :colorize, :blue)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# def test_singleton_that_accepts_object
|
|
121
|
+
# assert_equal "whatever (colorized in )", "whatever".singleton_that_accepts_object(self, :colorize2)
|
|
122
|
+
# assert_equal "whatever (colorized in blue)", "whatever".singleton_that_accepts_object(self, :colorize2, :blue)
|
|
123
|
+
# end
|
|
124
|
+
# def colorize2(color = nil)
|
|
125
|
+
# self + " (colorized2 in #{color})"
|
|
126
|
+
# end
|
|
127
|
+
end
|
|
128
|
+
=end
|
|
129
|
+
|
|
@@ -0,0 +1,111 @@
|
|
|
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
|
+
# * Names considered:
|
|
8
|
+
# * intersection (since there's already a Regexp#union), but unlike Regexp#union, it really doesn't seem like this method lends itself to a name from set theory. Mostly because unlike when dealing with sets (or unioned Regexps), *order matters* here.
|
|
9
|
+
# * merge, concat, sum, add, combines
|
|
10
|
+
# * join -- Settled on this because it's a lot like File.join: it combines the given pieces, *in order*, to make a whole.
|
|
11
|
+
#++
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Regexp
|
|
15
|
+
# Returns a Regexp that results from interpolating each of the given +elements+ into an empty regular expression.
|
|
16
|
+
# /ab/ == Regexp.join(/a/, /b/) # except spelled differently
|
|
17
|
+
# Accepts both strings and Regexp's as +elements+ to join together. Strings that are passed in will be escaped (so characters like '*' will lose all of the Regexp powers that they would otherwise have and are treated as literals).
|
|
18
|
+
#
|
|
19
|
+
# Serving suggestion: Use it to check if the +actual+ string in an <tt>assert_match</tt> contains certain literal strings, which may be separated by any number of characters or lines that we don't care about. In other words, use it to see if a string contains the necessary "keywords" or "key phrases"...
|
|
20
|
+
# assert_match Regexp.join(
|
|
21
|
+
# 'keyword1',
|
|
22
|
+
# /.*/m,
|
|
23
|
+
# 'keyword2'
|
|
24
|
+
# ), some_method()
|
|
25
|
+
# # where some_method() returns "keyword1 blah blah blah keyword2"
|
|
26
|
+
#
|
|
27
|
+
def self.join(*elements)
|
|
28
|
+
elements.inject(//) do |accumulator, element|
|
|
29
|
+
accumulator + element
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Pads the +elements+ (which may be strings or Regexp's) with /.*/ (match any number of characters) patterns.
|
|
34
|
+
# Pass :multi_line => true if you want /.*/m as the padding pattern instead.
|
|
35
|
+
def self.loose_join(*elements)
|
|
36
|
+
options = (if elements.last.is_a?(Hash) then elements.pop else {} end)
|
|
37
|
+
multi_line = options[:multi_line] || options[:m]
|
|
38
|
+
padding = (multi_line ? /.*/m : /.*/)
|
|
39
|
+
elements.inject(//) do |accumulator, element|
|
|
40
|
+
accumulator + padding + element
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# /a/ + /b/ == /ab/
|
|
45
|
+
# Actually, the way it's currently implemented, it is
|
|
46
|
+
# /a/ + /b/ == /(?-mix:a)(?-mix:b)/
|
|
47
|
+
# But they seem to be functionally equivalent despite the different spellings.
|
|
48
|
+
def +(other)
|
|
49
|
+
other = Regexp.escape(other) if other.is_a?(String)
|
|
50
|
+
/#{self}#{other}/
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# _____ _
|
|
58
|
+
# |_ _|__ ___| |_
|
|
59
|
+
# | |/ _ \/ __| __|
|
|
60
|
+
# | | __/\__ \ |_
|
|
61
|
+
# |_|\___||___/\__|
|
|
62
|
+
#
|
|
63
|
+
=begin test
|
|
64
|
+
require 'test/unit'
|
|
65
|
+
|
|
66
|
+
class TheTest < Test::Unit::TestCase
|
|
67
|
+
def test_1_simple_letters
|
|
68
|
+
assert_equal /(?-mix:)(?-mix:b)/, // + /b/
|
|
69
|
+
assert_equal /(?-mix:)b/, // + 'b'
|
|
70
|
+
assert_equal /(?-mix:a)(?-mix:b)/, /a/ + /b/
|
|
71
|
+
assert_equal /(?-mix:a)b/, /a/ + 'b'
|
|
72
|
+
assert_equal /(?-mix:(?-mix:(?-mix:)a)b)c/, Regexp.join('a', 'b', 'c')
|
|
73
|
+
#assert_equal /(?-mix:(?-mix:(?-mix:)a)b)c/, Regexp.join(/a/, /b/, /c/)
|
|
74
|
+
assert_equal 2, '__abc__' =~ Regexp.join('a', 'b', 'c')
|
|
75
|
+
assert_equal 2, '__abc__' =~ Regexp.join(/a/, /b/, /c/)
|
|
76
|
+
assert_equal nil, '__a.c__' =~ Regexp.join('a', 'b', 'c')
|
|
77
|
+
assert_equal nil, '__a.c__' =~ Regexp.join(/a/, /b/, /c/)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def test_2_escaping
|
|
81
|
+
assert_equal /(?-mix:)\./, // + '.' # Escaped
|
|
82
|
+
assert_equal /(?-mix:)(?-mix:.)/, // + /./ # Not escaped
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def test_3
|
|
86
|
+
assert_match Regexp.join(
|
|
87
|
+
'keyword1',
|
|
88
|
+
/.*/m,
|
|
89
|
+
'keyword2'
|
|
90
|
+
),
|
|
91
|
+
'keyword1
|
|
92
|
+
asuethausnthauesth
|
|
93
|
+
blah blah blah
|
|
94
|
+
keyword2'
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def test_loose_join
|
|
98
|
+
regexp = Regexp.loose_join('keyword1', 'keyword2')
|
|
99
|
+
assert_match regexp, 'keyword1 blah blah blah keyword2'
|
|
100
|
+
assert_equal nil, "keyword1 blah\nblah\nblah keyword2" =~ regexp
|
|
101
|
+
end
|
|
102
|
+
def test_loose_join_multiline
|
|
103
|
+
regexp = Regexp.loose_join('keyword1', 'keyword2', :m => true)
|
|
104
|
+
assert_match regexp, 'keyword1 blah blah blah keyword2'
|
|
105
|
+
assert_match regexp, "keyword1 blah\nblah\nblah keyword2"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
end
|
|
109
|
+
=end
|
|
110
|
+
|
|
111
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Author:: Tyler Rick
|
|
3
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
|
4
|
+
# License:: Ruby License
|
|
5
|
+
# Submit to Facets?:: Yes
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
class String
|
|
9
|
+
# Strips out everything except digits.
|
|
10
|
+
def digits_only
|
|
11
|
+
self.gsub(/[^0-9]/, "")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# _____ _
|
|
16
|
+
# |_ _|__ ___| |_
|
|
17
|
+
# | |/ _ \/ __| __|
|
|
18
|
+
# | | __/\__ \ |_
|
|
19
|
+
# |_|\___||___/\__|
|
|
20
|
+
#
|
|
21
|
+
=begin test
|
|
22
|
+
class TheTest < Test::Unit::TestCase
|
|
23
|
+
def test_digits_only
|
|
24
|
+
assert_equal "123", "$!@)(*&abc123[]{}".digits_only
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
=end
|