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,40 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Author:: Tyler Rick
|
|
3
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
|
4
|
+
# License:: Ruby License
|
|
5
|
+
# Submit to Facets?:: No!
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
# Depends on some niceties from ActiveSupport (which really should be in core Ruby but aren't)...
|
|
9
|
+
require "rubygems"
|
|
10
|
+
require "active_support"
|
|
11
|
+
require "pp"
|
|
12
|
+
|
|
13
|
+
class Date
|
|
14
|
+
# These should be moved elsewhere because they are subjective and depend on the context where they're used.
|
|
15
|
+
def date_for_report
|
|
16
|
+
strftime("%b %d, %Y") # Example: "Jun 18, 2006"
|
|
17
|
+
end
|
|
18
|
+
def month_for_report
|
|
19
|
+
strftime("%B %Y") # Example: "June 2006"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# _____ _
|
|
24
|
+
# |_ _|__ ___| |_
|
|
25
|
+
# | |/ _ \/ __| __|
|
|
26
|
+
# | | __/\__ \ |_
|
|
27
|
+
# |_|\___||___/\__|
|
|
28
|
+
#
|
|
29
|
+
=begin test
|
|
30
|
+
class TheTest < Test::Unit::TestCase
|
|
31
|
+
def test_date_for_report
|
|
32
|
+
assert_equal 'Jun 18, 2006', Date.new(2006, 6, 18).date_for_report()
|
|
33
|
+
assert_equal 'Jun 03, 2006', Date.new(2006, 6, 3).date_for_report()
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_month_for_report
|
|
37
|
+
assert_equal 'June 2006', Date.new(2006, 6).month_for_report()
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
=end
|
|
@@ -0,0 +1,31 @@
|
|
|
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 'date'
|
|
9
|
+
require 'rubygems'
|
|
10
|
+
require 'facets/core/date/to_time'
|
|
11
|
+
|
|
12
|
+
class Date
|
|
13
|
+
def iso8601
|
|
14
|
+
# Useful for SQL dates, among other things
|
|
15
|
+
to_time().iso8601()[0..9]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# _____ _
|
|
20
|
+
# |_ _|__ ___| |_
|
|
21
|
+
# | |/ _ \/ __| __|
|
|
22
|
+
# | | __/\__ \ |_
|
|
23
|
+
# |_|\___||___/\__|
|
|
24
|
+
#
|
|
25
|
+
=begin test
|
|
26
|
+
class TheTest < Test::Unit::TestCase
|
|
27
|
+
def test_iso8601
|
|
28
|
+
assert_equal '2006-07-18', Date.civil(2006, 7, 18).iso8601()
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
=end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Author:: Tyler Rick
|
|
3
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
|
4
|
+
# License:: Ruby License
|
|
5
|
+
# Submit to Facets?:: Not sure.
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
# Depends on some niceties from ActiveSupport (which really should be in core Ruby but aren't)... Date.new(a, b, c)
|
|
9
|
+
require "rubygems"
|
|
10
|
+
require "active_support"
|
|
11
|
+
|
|
12
|
+
# Attempts in part to make the Date class do everything (or at least some of the things) that the Time class can do (ActiveSupport::CoreExtensions::Time::Calculations).
|
|
13
|
+
# Maybe that would be better accomplished with a method_missing() that calls to_time.send(:the_same_method) if Time.respond_to?(:that_method).
|
|
14
|
+
class Date
|
|
15
|
+
|
|
16
|
+
# This is based on the implementation of Time.step. The main difference is that it uses
|
|
17
|
+
# >>= (increment by 1 month) instead of += (increment by 1 day).
|
|
18
|
+
def month_step(max, step, &block) # { |date| ...}
|
|
19
|
+
time = self
|
|
20
|
+
op = [:-,:<=,:>=][step<=>0]
|
|
21
|
+
while time.__send__(op, max)
|
|
22
|
+
block.call time
|
|
23
|
+
time >>= step
|
|
24
|
+
end
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Step forward one month at a time until we reach max (inclusive), yielding each date as we go
|
|
29
|
+
def months_upto(max, &block) # { |date| ...}
|
|
30
|
+
month_step(max, +1, &block)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_month
|
|
34
|
+
Month.new(year, month)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def next_month
|
|
38
|
+
# Uses http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Time/Calculations.html#M000336
|
|
39
|
+
self.to_time.next_month
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# _____ _
|
|
45
|
+
# |_ _|__ ___| |_
|
|
46
|
+
# | |/ _ \/ __| __|
|
|
47
|
+
# | | __/\__ \ |_
|
|
48
|
+
# |_|\___||___/\__|
|
|
49
|
+
#
|
|
50
|
+
=begin test
|
|
51
|
+
class TheTest < Test::Unit::TestCase
|
|
52
|
+
|
|
53
|
+
#-------------------------------------------------------------------------------------------------
|
|
54
|
+
# Ranges, step, and upto for *days*
|
|
55
|
+
# (This is built-in behavior.)
|
|
56
|
+
|
|
57
|
+
def test_step
|
|
58
|
+
list = []
|
|
59
|
+
collect_as_array = lambda do |date|
|
|
60
|
+
list << date
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
list = []
|
|
64
|
+
Date.new(2006, 6, 1).step(Date.new(2006, 6, 3), 1, &collect_as_array)
|
|
65
|
+
assert_equal [
|
|
66
|
+
Date.new(2006, 6, 1),
|
|
67
|
+
Date.new(2006, 6, 2),
|
|
68
|
+
Date.new(2006, 6, 3)
|
|
69
|
+
],
|
|
70
|
+
list
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def test_range
|
|
74
|
+
list = Date.new(2006, 6, 1)..Date.new(2006, 6, 3)
|
|
75
|
+
assert_equal Range.new(Date.new(2006, 6, 1), Date.new(2006, 6, 3)), list
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
#-------------------------------------------------------------------------------------------------
|
|
79
|
+
# Ranges, step, and upto for *months*
|
|
80
|
+
|
|
81
|
+
def test_month_step
|
|
82
|
+
list = []
|
|
83
|
+
collect_as_array = lambda do |date|
|
|
84
|
+
list << date
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
list = []
|
|
88
|
+
Date.new(2006, 6, 1).month_step(Date.new(2006, 7, 1), 1, &collect_as_array)
|
|
89
|
+
assert_equal [
|
|
90
|
+
Date.new(2006, 6, 1),
|
|
91
|
+
Date.new(2006, 7, 1)
|
|
92
|
+
],
|
|
93
|
+
list
|
|
94
|
+
|
|
95
|
+
# Test that it ignores days
|
|
96
|
+
list = []
|
|
97
|
+
Date.new(2006, 6, 1).month_step(Date.new(2006, 8, 31), 1, &collect_as_array)
|
|
98
|
+
assert_equal [
|
|
99
|
+
Date.new(2006, 6, 1),
|
|
100
|
+
Date.new(2006, 7, 1),
|
|
101
|
+
Date.new(2006, 8, 1)
|
|
102
|
+
],
|
|
103
|
+
list
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def test_months_upto
|
|
107
|
+
list = []
|
|
108
|
+
collect_as_array = lambda do |date|
|
|
109
|
+
list << date
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
list = []
|
|
113
|
+
Date.new(2006, 6, 1).months_upto(Date.new(2006, 7, 1), &collect_as_array)
|
|
114
|
+
assert_equal [
|
|
115
|
+
Date.new(2006, 6, 1),
|
|
116
|
+
Date.new(2006, 7, 1)
|
|
117
|
+
],
|
|
118
|
+
list
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
=end
|
|
122
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Author:: Nolan Cafferky
|
|
3
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
|
4
|
+
# License:: Ruby License
|
|
5
|
+
# Submit to Facets?:: Yes.
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Dir
|
|
10
|
+
# Much like each(), except the "." and ".." special files
|
|
11
|
+
# are ignored.
|
|
12
|
+
def each_child
|
|
13
|
+
each do |file|
|
|
14
|
+
yield file if file != "." and file != ".."
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# _____ _
|
|
21
|
+
# |_ _|__ ___| |_
|
|
22
|
+
# | |/ _ \/ __| __|
|
|
23
|
+
# | | __/\__ \ |_
|
|
24
|
+
# |_|\___||___/\__|
|
|
25
|
+
#
|
|
26
|
+
=begin test
|
|
27
|
+
|
|
28
|
+
require 'fileutils'
|
|
29
|
+
|
|
30
|
+
class TheTest < Test::Unit::TestCase
|
|
31
|
+
def setup
|
|
32
|
+
@base_path = "dir_extensions_test_test_each_child"
|
|
33
|
+
make_test_files @base_path
|
|
34
|
+
end
|
|
35
|
+
def teardown
|
|
36
|
+
FileUtils.remove_entry_secure @base_path
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_each_child
|
|
40
|
+
Dir.open(@base_path) do |d|
|
|
41
|
+
results = []
|
|
42
|
+
d.each_child { |file| results << file }
|
|
43
|
+
assert_equal 3, results.size
|
|
44
|
+
assert results.include?("foo")
|
|
45
|
+
assert results.include?("bar")
|
|
46
|
+
assert results.include?("foobar")
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def make_test_files base_path
|
|
51
|
+
Dir.mkdir( base_path)
|
|
52
|
+
FileUtils.touch(base_path + "/foo")
|
|
53
|
+
FileUtils.touch(base_path + "/bar")
|
|
54
|
+
Dir.mkdir( base_path + "/foobar")
|
|
55
|
+
FileUtils.touch(base_path + "/foobar/baz")
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
=end
|
|
@@ -0,0 +1,69 @@
|
|
|
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 'enumerator'
|
|
9
|
+
module Enumerable
|
|
10
|
+
|
|
11
|
+
# The core Enumerable module provides the following enumerator methods;
|
|
12
|
+
# * <tt>enum_cons()</tt>
|
|
13
|
+
# * <tt>enum_slice()</tt>
|
|
14
|
+
# * <tt>enum_with_index()</tt>
|
|
15
|
+
# but for some reason they didn't provide a generic <tt>enum()</tt> method for the cases they didn't think of!
|
|
16
|
+
#
|
|
17
|
+
# +enum+ lets you turn *any* iterator into a general-purpose <tt>Enumerator</tt>, which, according to the RDocs, is
|
|
18
|
+
# "A class which provides a method `<tt>each</tt>' to be used as an <tt>Enumerable</tt> object."
|
|
19
|
+
#
|
|
20
|
+
# This lets you turn any '<tt>each'-type</tt> iterator (<tt>each_byte</tt>, <tt>each_line</tt>, ...) into a
|
|
21
|
+
# '<tt>map</tt>'-type iterator (one that returns a collection), or into an array, etc.
|
|
22
|
+
#
|
|
23
|
+
# So if an object responds to <tt>:each_line</tt> but not to <tt>:map_lines</tt> or <tt>:lines</tt>, you could just do:
|
|
24
|
+
# object.enum(:each_line).map { block }
|
|
25
|
+
# object.enum(:each_line).min
|
|
26
|
+
# object.enum(:each_line).grep /pattern/
|
|
27
|
+
# lines = object.enum(:each_line).to_a
|
|
28
|
+
#
|
|
29
|
+
# If no iterator is specified, <tt>:each</tt> is assumed:
|
|
30
|
+
# object.enum.map { block }
|
|
31
|
+
#
|
|
32
|
+
# More examples:
|
|
33
|
+
# Dir.new('.').enum.to_a
|
|
34
|
+
# #=> ['file1', 'file2']
|
|
35
|
+
#
|
|
36
|
+
# "abc".enum(:each_byte).map{|byte| byte.chr.upcase}
|
|
37
|
+
# #=> ["A", "B", "C"]
|
|
38
|
+
#
|
|
39
|
+
def enum(iterator = :each)
|
|
40
|
+
Enumerable::Enumerator.new(self, iterator)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# _____ _
|
|
46
|
+
# |_ _|__ ___| |_
|
|
47
|
+
# | |/ _ \/ __| __|
|
|
48
|
+
# | | __/\__ \ |_
|
|
49
|
+
# |_|\___||___/\__|
|
|
50
|
+
#
|
|
51
|
+
=begin test
|
|
52
|
+
require 'test/unit'
|
|
53
|
+
|
|
54
|
+
class TheTest < Test::Unit::TestCase
|
|
55
|
+
def test_1
|
|
56
|
+
# @options.enum(:each).map { |key, value|
|
|
57
|
+
# values = [value].flatten
|
|
58
|
+
# key +
|
|
59
|
+
# (values.empty? ? " #{flatten.join(' ')}" : '')
|
|
60
|
+
# }.join(' ')
|
|
61
|
+
|
|
62
|
+
# Yes we could use the built-in Array#map method, but...not every class that provides iterators (each, ...) provides a map().
|
|
63
|
+
assert_equal ['A', 'B', 'C'], ['a', 'b', 'c'].enum(:each).map {|v| v.upcase}
|
|
64
|
+
end
|
|
65
|
+
def test_2
|
|
66
|
+
assert Dir.new('.').enum.to_a.size > 0
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
=end
|
|
@@ -0,0 +1,109 @@
|
|
|
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 Enumerable
|
|
12
|
+
# Returns an array containing all _consecutive_ elements of +enum+ for which +block+ is not false, starting at the first element.
|
|
13
|
+
# So it is very much like select, only it stops searching as soon as <tt>block</tt> ceases to be true. (That means it will stop searching immediately if the first element doesn't match.)
|
|
14
|
+
#
|
|
15
|
+
# This might be preferable to +select+, for example, if:
|
|
16
|
+
# * you have a very large collection of elements
|
|
17
|
+
# * the desired elements are expected to all be consecutively occuring and are all at the beginning of the collection
|
|
18
|
+
# * it would be costly to continue iterating all the way to the very end
|
|
19
|
+
#
|
|
20
|
+
# This is probably only useful for collections that have some kind of predictable ordering (such as Arrays).
|
|
21
|
+
#
|
|
22
|
+
# AKA: select_top_elements_that_match
|
|
23
|
+
#
|
|
24
|
+
def select_until(inclusive = false, &block)
|
|
25
|
+
selected = []
|
|
26
|
+
inclusive ? (
|
|
27
|
+
each do |item|
|
|
28
|
+
selected << item
|
|
29
|
+
break if block.call(item)
|
|
30
|
+
end
|
|
31
|
+
) : (
|
|
32
|
+
each do |item|
|
|
33
|
+
break if block.call(item)
|
|
34
|
+
selected << item
|
|
35
|
+
end
|
|
36
|
+
)
|
|
37
|
+
selected
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def select_while(&block)
|
|
41
|
+
selected = []
|
|
42
|
+
each do |item|
|
|
43
|
+
break if !block.call(item)
|
|
44
|
+
selected << item
|
|
45
|
+
end
|
|
46
|
+
selected
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# _____ _
|
|
55
|
+
# |_ _|__ ___| |_
|
|
56
|
+
# | |/ _ \/ __| __|
|
|
57
|
+
# | | __/\__ \ |_
|
|
58
|
+
# |_|\___||___/\__|
|
|
59
|
+
#
|
|
60
|
+
=begin test
|
|
61
|
+
require 'test/unit'
|
|
62
|
+
|
|
63
|
+
class TheTest < Test::Unit::TestCase
|
|
64
|
+
def test_1
|
|
65
|
+
assert_equal [1, 2], (1..4).select_while {|i| i <= 2}
|
|
66
|
+
assert_equal [1, 2], (1..4).select_until {|i| i == 3}
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_not_same_as_select
|
|
70
|
+
# Ah, yes, it behaves the same as select in *this* simple case:
|
|
71
|
+
assert_equal [1, 2], (1..4).select {|i| i <= 2}
|
|
72
|
+
|
|
73
|
+
# But what about _this_ one... hmm?
|
|
74
|
+
assert_equal [1, 2], [1, 2, 3, 2, 1].select_while {|i| i <= 2}
|
|
75
|
+
assert_equal [1, 2, 2, 1], [1, 2, 3, 2, 1].select {|i| i <= 2} # Not the same! Keyword: _consecutive_.
|
|
76
|
+
|
|
77
|
+
# Or _this_ one...
|
|
78
|
+
assert_equal [1, 2, 1], [1, 2, 1, 99, 2].select_while {|i| i <= 2}
|
|
79
|
+
assert_equal [1, 2], [1, 2, 1, 99, 2].select {|i| i <= 2}.uniq # Even this isn't the same.
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def test_inclusive_option
|
|
83
|
+
assert_equal [
|
|
84
|
+
'def cabbage',
|
|
85
|
+
' :cabbage',
|
|
86
|
+
], [
|
|
87
|
+
'def cabbage',
|
|
88
|
+
' :cabbage',
|
|
89
|
+
'end',
|
|
90
|
+
].select_until {|line| line =~ /end/}
|
|
91
|
+
# Not far enough. We actually want to *include* that last element.
|
|
92
|
+
|
|
93
|
+
assert_equal [
|
|
94
|
+
'def cabbage',
|
|
95
|
+
' :cabbage',
|
|
96
|
+
'end',
|
|
97
|
+
], [
|
|
98
|
+
'def cabbage',
|
|
99
|
+
' :cabbage',
|
|
100
|
+
'end',
|
|
101
|
+
'def carrot',
|
|
102
|
+
' :carrot',
|
|
103
|
+
'end',
|
|
104
|
+
].select_until(true) {|line| line =~ /end/}
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
=end
|
|
108
|
+
|
|
109
|
+
|