qualitysmith_extensions 0.0.3
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 +72 -0
- data/lib/qualitysmith_extensions/all.rb +2 -0
- data/lib/qualitysmith_extensions/array/all.rb +2 -0
- data/lib/qualitysmith_extensions/array/average.rb +42 -0
- data/lib/qualitysmith_extensions/array/expand_ranges.rb +48 -0
- data/lib/qualitysmith_extensions/array/group_by.rb +112 -0
- data/lib/qualitysmith_extensions/array/sequence.rb +64 -0
- data/lib/qualitysmith_extensions/array/shell_escape.rb +34 -0
- data/lib/qualitysmith_extensions/array/to_a_recursive.rb +39 -0
- data/lib/qualitysmith_extensions/array/to_query_string.rb +94 -0
- data/lib/qualitysmith_extensions/collection_extensions_for_cgi.rb +2 -0
- data/lib/qualitysmith_extensions/console/command.facets.1.8.51.rb +749 -0
- data/lib/qualitysmith_extensions/console/command.rb +940 -0
- data/lib/qualitysmith_extensions/date/all.rb +2 -0
- data/lib/qualitysmith_extensions/date/deprecated.rb +38 -0
- data/lib/qualitysmith_extensions/date/iso8601.rb +29 -0
- data/lib/qualitysmith_extensions/date/month_ranges.rb +120 -0
- data/lib/qualitysmith_extensions/enumerable/enum.rb +72 -0
- data/lib/qualitysmith_extensions/file/exact_match_regexp.rb +32 -0
- data/lib/qualitysmith_extensions/file_test/binary_file.rb +108 -0
- data/lib/qualitysmith_extensions/filter_output.rb +107 -0
- data/lib/qualitysmith_extensions/global_variable_set.rb +151 -0
- data/lib/qualitysmith_extensions/hash/all.rb +2 -0
- data/lib/qualitysmith_extensions/hash/to_date.rb +32 -0
- data/lib/qualitysmith_extensions/hash/to_query_string.rb +119 -0
- data/lib/qualitysmith_extensions/kernel/all.rb +2 -0
- data/lib/qualitysmith_extensions/kernel/backtrace.rb +69 -0
- data/lib/qualitysmith_extensions/kernel/capture_output.rb +113 -0
- data/lib/qualitysmith_extensions/kernel/die.rb +34 -0
- data/lib/qualitysmith_extensions/kernel/require_all.rb +118 -0
- data/lib/qualitysmith_extensions/kernel/require_once.rb +16 -0
- data/lib/qualitysmith_extensions/month.rb +62 -0
- data/lib/qualitysmith_extensions/object/singleton.rb +95 -0
- data/lib/qualitysmith_extensions/simulate_input.rb +51 -0
- data/lib/qualitysmith_extensions/string/all.rb +2 -0
- data/lib/qualitysmith_extensions/string/digits_only.rb +25 -0
- data/lib/qualitysmith_extensions/string/md5.rb +27 -0
- data/lib/qualitysmith_extensions/string/shell_escape.rb +41 -0
- data/lib/qualitysmith_extensions/string/to_underscored_label.rb +35 -0
- data/lib/qualitysmith_extensions/test/assert_changed.rb +64 -0
- data/lib/qualitysmith_extensions/test/assert_exception.rb +63 -0
- data/lib/qualitysmith_extensions/test/assert_includes.rb +34 -0
- data/lib/qualitysmith_extensions/test/assert_user_error.rb +34 -0
- data/lib/qualitysmith_extensions/time/all.rb +2 -0
- data/lib/qualitysmith_extensions/time/deprecated.rb +29 -0
- data/test/all.rb +16 -0
- metadata +94 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
# Author:: Anthony Kaufman, Tyler Rick
|
2
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
3
|
+
# License:: Ruby License
|
4
|
+
# Submit to Facets?:: Yes.
|
5
|
+
|
6
|
+
autoload :CGI, 'cgi'
|
7
|
+
require 'rubygems'
|
8
|
+
require 'facets/core/kernel/require_local'
|
9
|
+
require_local '../array/to_query_string.rb'
|
10
|
+
|
11
|
+
class Hash
|
12
|
+
|
13
|
+
=begin rdoc
|
14
|
+
Converts into a string that can be used as the {query string}[http://en.wikipedia.org/wiki/Query_string] of a URL (for example, <tt>?key1=val1&key2=val2</tt>).
|
15
|
+
|
16
|
+
Example:
|
17
|
+
{
|
18
|
+
'colors' => ['red', 'blue'],
|
19
|
+
'username' => 'pineapple'
|
20
|
+
}.to_query_string('data')
|
21
|
+
==> "data[username]=pineapple&data[colors][]=red&data[colors][]=blue"
|
22
|
+
|
23
|
+
The hash can be nested as deeply as you want and can also contain arrays.
|
24
|
+
|
25
|
+
<tt>key</tt> is the name of the key in params that will receive this hash when you load the page. So, for example, if you go to page with this query string (key = "name"): <tt>?name[first]=Fred&name[last]=Fredson</tt>, params will be have a key "name", like so: <tt>{"name"=>{"last"=>"Fredson", "first"=>"Fred"}}</tt>.
|
26
|
+
|
27
|
+
{
|
28
|
+
'colors' => ['red', 'blue'],
|
29
|
+
'username' => 'pineapple'
|
30
|
+
}.to_query_string('data')
|
31
|
+
|
32
|
+
is equivalent to just writing your hash like so:
|
33
|
+
|
34
|
+
{
|
35
|
+
'data' => {
|
36
|
+
'colors' => ['red', 'blue'],
|
37
|
+
'username' => 'pineapple'
|
38
|
+
}
|
39
|
+
}.to_query_string()
|
40
|
+
=end
|
41
|
+
def to_query_string(key = '')
|
42
|
+
prefix = key.dup
|
43
|
+
elements = []
|
44
|
+
|
45
|
+
self.each_pair do |key, value|
|
46
|
+
key = CGI.escape key.to_s
|
47
|
+
key = prefix.length > 1 ? "#{prefix}[#{key}]" : key
|
48
|
+
if value.respond_to? :to_query_string
|
49
|
+
valuepre = value.dup
|
50
|
+
value = value.to_query_string(key)
|
51
|
+
#puts "#{key}#{valuepre.inspect} => #{value}"
|
52
|
+
elements << value
|
53
|
+
else
|
54
|
+
value = CGI.escape value.to_s
|
55
|
+
elements << key + '=' + value
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
elements.join('&')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# _____ _
|
64
|
+
# |_ _|__ ___| |_
|
65
|
+
# | |/ _ \/ __| __|
|
66
|
+
# | | __/\__ \ |_
|
67
|
+
# |_|\___||___/\__|
|
68
|
+
#
|
69
|
+
=begin test
|
70
|
+
class TheTest < Test::Unit::TestCase
|
71
|
+
def test_hash_to_query_string_nesting
|
72
|
+
data = {
|
73
|
+
'foo' => 'bar',
|
74
|
+
'names' => {
|
75
|
+
'common' => 'smith',
|
76
|
+
'uncommon' => {
|
77
|
+
:first => 'lance',
|
78
|
+
:last => 'wilheiminkauf'
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}
|
82
|
+
assert_equal 'foo=bar&names[common]=smith&names[uncommon][first]=lance&names[uncommon][last]=wilheiminkauf', data.to_query_string
|
83
|
+
end
|
84
|
+
def test_hash_to_query_string_nesting_2
|
85
|
+
data = {
|
86
|
+
'common' => 'smith',
|
87
|
+
'uncommon' => [
|
88
|
+
'frankenwatzel',
|
89
|
+
'wilheiminkauf'
|
90
|
+
]
|
91
|
+
}
|
92
|
+
assert_equal 'names[common]=smith&names[uncommon][]=frankenwatzel&names[uncommon][]=wilheiminkauf', data.to_query_string('names')
|
93
|
+
assert_equal( {'names' => data}.to_query_string(),
|
94
|
+
data.to_query_string('names') )
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_hash_to_query_string_encoding
|
98
|
+
data = {'f&r' => 'a w$'}
|
99
|
+
|
100
|
+
assert_equal 'f%26r=a+w%24', data.to_query_string
|
101
|
+
end
|
102
|
+
end
|
103
|
+
=end
|
104
|
+
|
105
|
+
=begin examples
|
106
|
+
require 'irb/xmp'
|
107
|
+
xmp <<End
|
108
|
+
{
|
109
|
+
'colors' => ['red', 'blue'],
|
110
|
+
'username' => 'pineapple'
|
111
|
+
}.to_query_string('data')
|
112
|
+
{
|
113
|
+
'data' => {
|
114
|
+
'colors' => ['red', 'blue'],
|
115
|
+
'username' => 'pineapple'
|
116
|
+
}
|
117
|
+
}.to_query_string()
|
118
|
+
End
|
119
|
+
=end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Author:: Tyler Rick
|
2
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
3
|
+
# License:: Ruby License
|
4
|
+
# Submit to Facets?:: Not sure. This might not be necessary if caller() actually works reliably.
|
5
|
+
|
6
|
+
require "rubygems"
|
7
|
+
require "facet/string/lines"
|
8
|
+
|
9
|
+
module Kernel
|
10
|
+
# Equivalent to calling caller(0)
|
11
|
+
def backtrace
|
12
|
+
full_backtrace = caller(0)
|
13
|
+
return full_backtrace[1..-1] # We don't want this call to backtrace showing up in the backtrace, so skip top 1 frame.
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns a human-readable backtrace
|
17
|
+
def pretty_backtrace
|
18
|
+
"Backtrace:\n" +
|
19
|
+
backtrace[1..-1].map{|frame| "* " + frame}.join("\n")
|
20
|
+
end
|
21
|
+
|
22
|
+
# I thought I ran into some case where it didn't work to use caller(0)...which prompted me to do it this way (raise and rescue an exception)...but now I can't duplicate that problem, so I will deprecate this method.
|
23
|
+
def backtrace_using_exception
|
24
|
+
begin
|
25
|
+
raise "Where am I?"
|
26
|
+
rescue Exception => exception
|
27
|
+
full_backtrace = exception.backtrace
|
28
|
+
return full_backtrace[1..-1] # We don't want this call to backtrace showing up in the backtrace, so skip top 1 frame.
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# _____ _
|
35
|
+
# |_ _|__ ___| |_
|
36
|
+
# | |/ _ \/ __| __|
|
37
|
+
# | | __/\__ \ |_
|
38
|
+
# |_|\___||___/\__|
|
39
|
+
#
|
40
|
+
=begin test
|
41
|
+
class TheTest < Test::Unit::TestCase
|
42
|
+
def test_1_level
|
43
|
+
assert_match /^.*backtrace.rb:\d*:in `test_1_level'$/, backtrace[0]
|
44
|
+
assert_match /^.*testcase.rb:\d*:in `__send__'$/, backtrace[1]
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_pretty_backtrace
|
48
|
+
assert_match /^Backtrace:$/, pretty_backtrace.lines[0]
|
49
|
+
assert_match /^.*backtrace.rb:\d*:in `test_pretty_backtrace'$/, pretty_backtrace.lines[1]
|
50
|
+
assert_match /^.*testcase.rb:\d*:in `__send__'$/, pretty_backtrace.lines[2]
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_2_levels
|
54
|
+
assert_match /^.*backtrace.rb:\d*:in `a_method_that_returns_a_backtrace'$/, a_method_that_returns_a_backtrace[0]
|
55
|
+
assert_match /^.*backtrace.rb:\d*:in `test_2_levels'$/, a_method_that_returns_a_backtrace[1]
|
56
|
+
assert_match /^.*testcase.rb:\d*:in `__send__'$/, a_method_that_returns_a_backtrace[2]
|
57
|
+
end
|
58
|
+
|
59
|
+
def a_method_that_returns_a_backtrace
|
60
|
+
backtrace
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_all_methods_of_getting_backtrace_are_equivalent
|
64
|
+
assert_equal backtrace_using_exception, backtrace
|
65
|
+
assert_equal backtrace_using_exception, caller(0)
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
=end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# Author:: Tyler Rick
|
2
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
3
|
+
# License:: Ruby License
|
4
|
+
# Submit to Facets?:: Yes
|
5
|
+
|
6
|
+
# :todo: Can we find a simpler way to do this based on facets' silence_stream?
|
7
|
+
#
|
8
|
+
# File lib/facets/core/kernel/silence_stream.rb, line 13
|
9
|
+
# def silence_stream(stream)
|
10
|
+
# old_stream = stream.dup
|
11
|
+
# stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
|
12
|
+
# stream.sync = true
|
13
|
+
# yield
|
14
|
+
# ensure
|
15
|
+
# stream.reopen(old_stream)
|
16
|
+
# end
|
17
|
+
|
18
|
+
require 'stringio'
|
19
|
+
require 'rubygems'
|
20
|
+
require 'facets/more/dictionary'
|
21
|
+
|
22
|
+
module Kernel
|
23
|
+
|
24
|
+
# Captures the output (stdout by default) that +block+ tries to generate and returns it as a string.
|
25
|
+
#
|
26
|
+
# output = capture_output($stderr) { noisy_command }
|
27
|
+
#
|
28
|
+
# output = capture_output([$stdout, $stderr]) do
|
29
|
+
# noisy_command
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# *Note*: If you specify more than one output stream, the entire results of each will be concatenated <i>in the order you listed them</i>, not necessarily in the order that you wrote _to_ those streams.
|
33
|
+
def capture_output(output_streams = $stdout, &block)
|
34
|
+
output_streams = [output_streams] unless output_streams.is_a? Array
|
35
|
+
|
36
|
+
saved_output_streams = Dictionary.new
|
37
|
+
output_streams.each do |output_stream|
|
38
|
+
case output_stream.object_id
|
39
|
+
when $stdout.object_id
|
40
|
+
saved_output_streams[:$stdout] = $stdout
|
41
|
+
$stdout = StringIO.new
|
42
|
+
when $stderr.object_id
|
43
|
+
saved_output_streams[:$stderr] = $stderr
|
44
|
+
$stderr = StringIO.new
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
what_they_tried_to_output = ''
|
49
|
+
begin
|
50
|
+
yield
|
51
|
+
rescue Exception
|
52
|
+
raise
|
53
|
+
ensure
|
54
|
+
saved_output_streams.each do |name, output_stream|
|
55
|
+
case name
|
56
|
+
when :$stdout
|
57
|
+
what_they_tried_to_output += $stdout.string
|
58
|
+
when :$stderr
|
59
|
+
what_they_tried_to_output += $stderr.string
|
60
|
+
end
|
61
|
+
|
62
|
+
# Restore the original output_stream that we saved.
|
63
|
+
case name
|
64
|
+
when :$stdout
|
65
|
+
$stdout = saved_output_streams[:$stdout]
|
66
|
+
when :$stderr
|
67
|
+
$stderr = saved_output_streams[:$stderr]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
return what_they_tried_to_output
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
# _____ _
|
77
|
+
# |_ _|__ ___| |_
|
78
|
+
# | |/ _ \/ __| __|
|
79
|
+
# | | __/\__ \ |_
|
80
|
+
# |_|\___||___/\__|
|
81
|
+
#
|
82
|
+
=begin test
|
83
|
+
require 'test/unit'
|
84
|
+
|
85
|
+
def noisy_command
|
86
|
+
puts "Some lovely message"
|
87
|
+
$stderr.puts "Some lovely error message"
|
88
|
+
end
|
89
|
+
def noisy_command_with_error
|
90
|
+
puts "Some lovely message"
|
91
|
+
$stderr.puts "Some lovely error message"
|
92
|
+
raise 'an error'
|
93
|
+
end
|
94
|
+
|
95
|
+
class TheTest < Test::Unit::TestCase
|
96
|
+
def test_capture_all
|
97
|
+
assert_equal "Some lovely message\nSome lovely error message\n", capture_output([$stdout, $stderr]) { noisy_command }
|
98
|
+
end
|
99
|
+
def test_capture_all__different_order
|
100
|
+
# This is, I suppose a limitation of StingIO. This behavior may change in a future version if a workaround is found. (Creating a new IO subclass, +TimestampedStringIO+, that keeps a timestamp for every thing you add to it so that the results of two such objects can be merged to yield chronological output.)
|
101
|
+
assert_equal "Some lovely error message\nSome lovely message\n", capture_output([$stderr, $stdout]) { noisy_command }
|
102
|
+
end
|
103
|
+
def test_capture_stdout
|
104
|
+
assert_equal "Some lovely message\n", capture_output($stdout) { noisy_command }
|
105
|
+
end
|
106
|
+
def test_capture_stderr
|
107
|
+
assert_equal "Some lovely error message\n", capture_output($stderr) { noisy_command }
|
108
|
+
end
|
109
|
+
def test_when_an_error_is_raised_from_block
|
110
|
+
assert_raise(RuntimeError) { capture_output() { noisy_command_with_error } }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
=end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Author:: Tyler Rick
|
2
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
3
|
+
# License:: Ruby License
|
4
|
+
# Submit to Facets?:: Yes
|
5
|
+
|
6
|
+
module Kernel
|
7
|
+
def die(message)
|
8
|
+
$stderr.puts message
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# _____ _
|
14
|
+
# |_ _|__ ___| |_
|
15
|
+
# | |/ _ \/ __| __|
|
16
|
+
# | | __/\__ \ |_
|
17
|
+
# |_|\___||___/\__|
|
18
|
+
#
|
19
|
+
=begin test
|
20
|
+
require 'qualitysmith_extensions/kernel/capture_output'
|
21
|
+
|
22
|
+
class TheTest < Test::Unit::TestCase
|
23
|
+
|
24
|
+
def test_1
|
25
|
+
stderr = capture_output $stderr do
|
26
|
+
assert_raise(SystemExit) do
|
27
|
+
die "Aggh! I'm dying!"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
assert_equal "Aggh! I'm dying!", stderr.chomp
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
=end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# Author:: Tyler Rick
|
2
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
3
|
+
# License:: Ruby License
|
4
|
+
# Submit to Facets?:: Yes
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'facets/more/filelist'
|
8
|
+
|
9
|
+
require 'facets/core/kernel/require_local'
|
10
|
+
require_local '../file/exact_match_regexp'
|
11
|
+
|
12
|
+
module Kernel
|
13
|
+
|
14
|
+
# Recursively <tt>require</tt>s all Ruby files in <tt>base_dir</tt> or any of its subdirectories.
|
15
|
+
# <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.
|
16
|
+
# <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.
|
17
|
+
#
|
18
|
+
# Note:
|
19
|
+
#
|
20
|
+
# Examples:
|
21
|
+
# require_all 'lib/', :exclude => [/ignore/, /bogus/] # will require 'lib/a.rb', 'lib/long/path/b.rb', but not 'lib/ignore/c.rb'
|
22
|
+
# require_all File.dirname(__FILE__), :exclude_files => ['blow_up_stuff.rb']
|
23
|
+
def require_all(base_dir, options = {})
|
24
|
+
base_dir += '/' unless base_dir[-1].chr == '/'
|
25
|
+
exclusions = nil
|
26
|
+
files = FileList[base_dir + "**/*.rb"]
|
27
|
+
files = files.exclude(*exclusions) if (exclusions = options.delete(:exclude))
|
28
|
+
files = files.exclude(*exclusions.map {|a| File.exact_match_regexp(a) }) if (exclusions = options.delete(:exclude_files))
|
29
|
+
|
30
|
+
files.each do |filename|
|
31
|
+
# puts "requiring #{filename}" if filename =~ /test/
|
32
|
+
require filename
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
# _____ _
|
39
|
+
# |_ _|__ ___| |_
|
40
|
+
# | |/ _ \/ __| __|
|
41
|
+
# | | __/\__ \ |_
|
42
|
+
# |_|\___||___/\__|
|
43
|
+
#
|
44
|
+
=begin test
|
45
|
+
require 'tmpdir'
|
46
|
+
require 'fileutils'
|
47
|
+
|
48
|
+
class TheTest < Test::Unit::TestCase
|
49
|
+
def setup
|
50
|
+
@main_subdir = 'require_all_test'
|
51
|
+
@base_dir = "#{Dir.tmpdir}/#{@main_subdir}"
|
52
|
+
FileUtils.mkdir @base_dir
|
53
|
+
FileUtils.mkdir_p @deep_dir = @base_dir + "/really/really/deep/subdir"
|
54
|
+
$loaded = Array.new(2)
|
55
|
+
end
|
56
|
+
def teardown
|
57
|
+
FileUtils.rm_rf @base_dir
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def test_repeat_requires
|
62
|
+
$loaded[0] = 0
|
63
|
+
File.open("#{@base_dir}/moo.rb", "w") {|f| f.puts "$loaded[0] += 1"}
|
64
|
+
require_all File.dirname(@base_dir)
|
65
|
+
assert_equal [1, nil], $loaded
|
66
|
+
|
67
|
+
require "#{@base_dir}/moo.rb"
|
68
|
+
assert_equal [1, nil], $loaded
|
69
|
+
|
70
|
+
# Good! It refuses to load it again, even if we drop the ".rb" part!
|
71
|
+
require "#{@base_dir}/moo"
|
72
|
+
assert_equal [1, nil], $loaded
|
73
|
+
|
74
|
+
# But, we can still trick it!
|
75
|
+
$LOAD_PATH << @base_dir
|
76
|
+
require "moo"
|
77
|
+
assert_equal [2, nil], $loaded
|
78
|
+
|
79
|
+
load "moo.rb"
|
80
|
+
assert_equal [3, nil], $loaded
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_deep_subdir
|
84
|
+
File.open("#{@base_dir}/flip.rb", "w") {|f| f.puts "$loaded[0] = true"}
|
85
|
+
File.open("#{@deep_dir}/flop.rb", "w") {|f| f.puts "$loaded[1] = true"}
|
86
|
+
|
87
|
+
require_all File.dirname(@base_dir)
|
88
|
+
assert_equal [true, true], $loaded
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_exclude_pattern
|
92
|
+
File.open("#{@base_dir}/require_me.rb", "w") {|f| f.puts "$loaded[0] = true"}
|
93
|
+
File.open("#{@base_dir}/please_ignore_me.rb", "w") {|f| f.puts "$loaded[1] = true"}
|
94
|
+
|
95
|
+
require_all File.dirname(@base_dir), :exclude => [/ignore/]
|
96
|
+
assert_equal [true, nil], $loaded
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_exclude_filename
|
100
|
+
File.open("#{@base_dir}/yes.rb", "w") {|f| f.puts "$loaded[0] = true"}
|
101
|
+
File.open("#{@base_dir}/all.rb", "w") {|f| f.puts "$loaded[1] = true"}
|
102
|
+
|
103
|
+
# :todo: Interesting how none of these patterns work. I would have expected them to. Is there a bug in FileList? Find out...
|
104
|
+
# /usr/lib/ruby/gems/1.8/gems/facets-1.8.51/lib/facets/more/filelist.rb
|
105
|
+
#require_all File.dirname(@base_dir), :exclude => ['all.rb']
|
106
|
+
#require_all File.dirname(@base_dir), :exclude => ['**/all']
|
107
|
+
#require_all File.dirname(@base_dir), :exclude => [/^all\.rb$/]
|
108
|
+
# This works, but it's too much to expect users to type out!:
|
109
|
+
#require_all File.dirname(@base_dir), :exclude => [/(\/|^)all\.rb$/]
|
110
|
+
|
111
|
+
# So...... I added an :exclude_files option so that people wouldn't have to!
|
112
|
+
require_all File.dirname(@base_dir), :exclude_files => ['all.rb']
|
113
|
+
|
114
|
+
assert_equal [true, nil], $loaded
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
=end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Author:: Tyler Rick
|
2
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
3
|
+
# License:: Ruby License
|
4
|
+
# Submit to Facets?:: No, not yet
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
|
8
|
+
module Kernel
|
9
|
+
# 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.
|
10
|
+
def require_once(name)
|
11
|
+
raise NotImplementedError
|
12
|
+
# store expand_path(name) in an array ($required_files or something)
|
13
|
+
# only do the require if it wasn't already in the array
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Author:: Tyler Rick
|
2
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
3
|
+
# License:: Ruby License
|
4
|
+
# Submit to Facets?:: Not sure. Who really cares about Months anyway?
|
5
|
+
|
6
|
+
require "rubygems"
|
7
|
+
require "active_support"
|
8
|
+
require File.dirname(__FILE__) + "/date/all"
|
9
|
+
|
10
|
+
class Month
|
11
|
+
include Comparable
|
12
|
+
attr_reader :year, :month
|
13
|
+
|
14
|
+
def initialize(year, month)
|
15
|
+
@year = year
|
16
|
+
@month = month
|
17
|
+
end
|
18
|
+
|
19
|
+
def succ
|
20
|
+
(to_date >> 1).to_month
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_date
|
24
|
+
Date.new(year, month)
|
25
|
+
end
|
26
|
+
|
27
|
+
def <=>(other)
|
28
|
+
#puts "#{self.inspect} <=> #{other.inspect}"
|
29
|
+
return self.to_date <=> other.to_date
|
30
|
+
end
|
31
|
+
|
32
|
+
def inspect
|
33
|
+
"#{@year}-#{@month}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
# _____ _
|
39
|
+
# |_ _|__ ___| |_
|
40
|
+
# | |/ _ \/ __| __|
|
41
|
+
# | | __/\__ \ |_
|
42
|
+
# |_|\___||___/\__|
|
43
|
+
#
|
44
|
+
=begin test
|
45
|
+
class TheTest < Test::Unit::TestCase
|
46
|
+
def test_months_range
|
47
|
+
range = Month.new(2006, 6)..Month.new(2006, 9)
|
48
|
+
assert_equal Range.new(Month.new(2006, 6), Month.new(2006, 9)), range
|
49
|
+
|
50
|
+
range = Date.new(2006, 6, 1).to_month..Date.new(2006, 9, 3).to_month
|
51
|
+
assert_equal Range.new(Month.new(2006, 6), Month.new(2006, 9)), range
|
52
|
+
|
53
|
+
assert_equal [
|
54
|
+
Month.new(2006, 6),
|
55
|
+
Month.new(2006, 7),
|
56
|
+
Month.new(2006, 8),
|
57
|
+
Month.new(2006, 9)
|
58
|
+
],
|
59
|
+
range.to_a
|
60
|
+
end
|
61
|
+
end
|
62
|
+
=end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# Author:: Tyler Rick
|
2
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
3
|
+
# License:: Ruby License
|
4
|
+
# Submit to Facets?:: Yes
|
5
|
+
# Developer notes::
|
6
|
+
# * Method name too long? Imagine if we wanted to string multiple calls together.
|
7
|
+
# * Ideas:
|
8
|
+
# * single_send
|
9
|
+
# * singleton_send
|
10
|
+
# * singleton_call
|
11
|
+
# * singleton
|
12
|
+
# * singsend
|
13
|
+
# * extend_send
|
14
|
+
# * extend_call
|
15
|
+
# * create_and_send
|
16
|
+
# * create_and_call
|
17
|
+
|
18
|
+
class Object
|
19
|
+
|
20
|
+
# Creates a singleton method and then calls it.
|
21
|
+
#
|
22
|
+
# More specificaly, it +extend+s +self+ with the methods from +moduule+ and then sends the supplied +message+ and +args+ (if any).
|
23
|
+
#
|
24
|
+
# Advantages:
|
25
|
+
# * Keeps things object-oriented. Better than having global/class methods.
|
26
|
+
# ** (<tt>"whatever".single_send(MyColorizer, :colorize).single_send(SomeOtherClass, :another_class_method)</tt> instead of <tt>SomeOtherClass::another_class_method(MyColorizer::colorize("whatever"))</tt>)
|
27
|
+
# ** Method calls are _listed_ in the order in which they are _called_.
|
28
|
+
# * Still lets you keep your methods in a namespace.
|
29
|
+
# * 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>.
|
30
|
+
# * Useful for cases where creating a subclass wouldn't help because the methods you are calling would still return instances of the base class.
|
31
|
+
#
|
32
|
+
# Disadvantages:
|
33
|
+
# * You have to have/create a *module* for the functions you want to use.
|
34
|
+
# ** Can't just call .sigleton(self, :some_method) if some_method is defined in self.
|
35
|
+
# ** So what do we call the module containing the "singleton method"? String::MyColorizer? MyColorizer::String? MyStringColorizer?
|
36
|
+
#
|
37
|
+
# Examples:
|
38
|
+
# "whatever".singleton(MyColorizer, :colorize, :blue)
|
39
|
+
#
|
40
|
+
def singleton(moduule, message, *args)
|
41
|
+
self.extend(moduule)
|
42
|
+
self.send(message, *args)
|
43
|
+
end
|
44
|
+
|
45
|
+
def singleton_that_accepts_object(object, method_name, *args)
|
46
|
+
# #class << self
|
47
|
+
# #self.instance_eval do
|
48
|
+
# self.class.module_eval do
|
49
|
+
# define_method(:colorize2, object.class.instance_method(:colorize2))
|
50
|
+
# end
|
51
|
+
# # raises "TypeError: bind argument must be an instance of TheTest"
|
52
|
+
|
53
|
+
# object.class.instance_method(method_name).
|
54
|
+
# bind(self)
|
55
|
+
# # raises "TypeError: bind argument must be an instance of TheTest"
|
56
|
+
|
57
|
+
# self.class.extend(object.class)
|
58
|
+
# self.class.send(:include, object.class)
|
59
|
+
# # raises "TypeError: wrong argument type Class (expected Module)"
|
60
|
+
self.send(method_name, *args)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
# _____ _
|
66
|
+
# |_ _|__ ___| |_
|
67
|
+
# | |/ _ \/ __| __|
|
68
|
+
# | | __/\__ \ |_
|
69
|
+
# |_|\___||___/\__|
|
70
|
+
#
|
71
|
+
=begin test
|
72
|
+
require 'test/unit'
|
73
|
+
|
74
|
+
module MyColorizer
|
75
|
+
def colorize(color = nil)
|
76
|
+
self + " (colorized in #{color})"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class TheTest < Test::Unit::TestCase
|
81
|
+
def test_1
|
82
|
+
assert_equal "whatever (colorized in )", "whatever".singleton(MyColorizer, :colorize)
|
83
|
+
assert_equal "whatever (colorized in blue)", "whatever".singleton(MyColorizer, :colorize, :blue)
|
84
|
+
end
|
85
|
+
|
86
|
+
# def test_2
|
87
|
+
# assert_equal "whatever (colorized in )", "whatever".singleton_that_accepts_object(self, :colorize2)
|
88
|
+
# assert_equal "whatever (colorized in blue)", "whatever".singleton_that_accepts_object(self, :colorize2, :blue)
|
89
|
+
# end
|
90
|
+
# def colorize2(color = nil)
|
91
|
+
# self + " (colorized2 in #{color})"
|
92
|
+
# end
|
93
|
+
end
|
94
|
+
=end
|
95
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# Author:: Tyler Rick
|
2
|
+
# Copyright:: Copyright (c) 2007 QualitySmith, Inc.
|
3
|
+
# License:: Ruby License
|
4
|
+
# Submit to Facets?:: Yes
|
5
|
+
# Developer notes:
|
6
|
+
# * Move to kernel/?
|
7
|
+
|
8
|
+
require 'stringio'
|
9
|
+
require 'rubygems'
|
10
|
+
|
11
|
+
# Simulates a user typing in +input_string+ on the keyboard.
|
12
|
+
#
|
13
|
+
# Useful for testing console apps that are ordinarily (they prompt the user for input).
|
14
|
+
#
|
15
|
+
# output = simulate_inpute('foo') do
|
16
|
+
# input = $stdin.gets
|
17
|
+
# capture_output { do_stuff() }
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
def simulate_input(input_string, &block)
|
21
|
+
|
22
|
+
original_stdin = $stdin
|
23
|
+
$stdin = StringIO.new(input_string, 'r')
|
24
|
+
|
25
|
+
begin
|
26
|
+
yield
|
27
|
+
rescue Exception
|
28
|
+
raise
|
29
|
+
ensure
|
30
|
+
$stdin = original_stdin
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
# _____ _
|
36
|
+
# |_ _|__ ___| |_
|
37
|
+
# | |/ _ \/ __| __|
|
38
|
+
# | | __/\__ \ |_
|
39
|
+
# |_|\___||___/\__|
|
40
|
+
#
|
41
|
+
=begin test
|
42
|
+
require 'test/unit'
|
43
|
+
|
44
|
+
class TheTest < Test::Unit::TestCase
|
45
|
+
def test_1
|
46
|
+
input_received = nil
|
47
|
+
simulate_input('foo') { input_received = $stdin.getc.chr }
|
48
|
+
assert_equal 'f', input_received
|
49
|
+
end
|
50
|
+
end
|
51
|
+
=end
|