AvantiConveniences 1.0.6
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/AvantiConveniences.gemspec +42 -0
- data/History.txt +32 -0
- data/Manifest.txt +26 -0
- data/README.txt +80 -0
- data/Rakefile +77 -0
- data/lib/arg_checks.rb +79 -0
- data/lib/array_extensions.rb +5 -0
- data/lib/avanti_conveniences.rb +13 -0
- data/lib/die.rb +5 -0
- data/lib/float_extensions.rb +3 -0
- data/lib/hash_extensions.rb +22 -0
- data/lib/string_extensions.rb +25 -0
- data/lib/text_formatter.rb +83 -0
- data/lib/time_extensions.rb +6 -0
- data/lib/uri_extensions.rb +23 -0
- data/test/test_arg_checks.rb +113 -0
- data/test/test_array_extensions.rb +36 -0
- data/test/test_avanti_conveniences.rb +9 -0
- data/test/test_die.rb +22 -0
- data/test/test_float_extensions.rb +17 -0
- data/test/test_hash_extensions.rb +23 -0
- data/test/test_string_extensions.rb +57 -0
- data/test/test_text_formatter.rb +81 -0
- data/test/test_time_extensions.rb +23 -0
- data/test/test_uri_extensions.rb +14 -0
- metadata +131 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = %q{AvantiConveniences}
|
|
5
|
+
s.version = "1.0.4"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
9
|
+
s.authors = ["Jamie Flournoy"]
|
|
10
|
+
s.date = %q{2009-03-20}
|
|
11
|
+
s.description = %q{AvantiConveniences is a set of convenience code for Ruby on Rails applications.}
|
|
12
|
+
s.email = ["jamie@pervasivecode.com"]
|
|
13
|
+
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
|
|
14
|
+
s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "lib/arg_checks.rb", "lib/avanti_conveniences.rb", "lib/hash_extensions.rb", "lib/string_extensions.rb", "lib/text_formatter.rb", "lib/uri_extensions.rb", "test/test_arg_checks.rb", "test/test_avanti_conveniences.rb", "test/test_hash_extensions.rb", "test/test_string_extensions.rb", "test/test_text_formatter.rb", "test/test_uri_extensions.rb"]
|
|
15
|
+
s.has_rdoc = true
|
|
16
|
+
s.homepage = %q{http://www.pervasivecode.com/blog/avanticonveniences/}
|
|
17
|
+
s.rdoc_options = ["--main", "README.txt"]
|
|
18
|
+
s.require_paths = ["lib"]
|
|
19
|
+
s.rubyforge_project = %q{avanticonveniences}
|
|
20
|
+
s.rubygems_version = %q{1.3.1}
|
|
21
|
+
s.summary = %q{AvantiConveniences is a set of convenience code for Ruby on Rails applications.}
|
|
22
|
+
s.test_files = ["test/test_arg_checks.rb", "test/test_avanti_conveniences.rb", "test/test_hash_extensions.rb", "test/test_string_extensions.rb", "test/test_text_formatter.rb", "test/test_uri_extensions.rb"]
|
|
23
|
+
|
|
24
|
+
if s.respond_to? :specification_version then
|
|
25
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
26
|
+
s.specification_version = 2
|
|
27
|
+
|
|
28
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
29
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 1.2.6"])
|
|
30
|
+
s.add_runtime_dependency(%q<text-hyphen>, [">= 1.0.0"])
|
|
31
|
+
s.add_development_dependency(%q<hoe>, [">= 1.11.0"])
|
|
32
|
+
else
|
|
33
|
+
s.add_dependency(%q<activesupport>, [">= 1.2.6"])
|
|
34
|
+
s.add_dependency(%q<text-hyphen>, [">= 1.0.0"])
|
|
35
|
+
s.add_dependency(%q<hoe>, [">= 1.11.0"])
|
|
36
|
+
end
|
|
37
|
+
else
|
|
38
|
+
s.add_dependency(%q<activesupport>, [">= 1.2.6"])
|
|
39
|
+
s.add_dependency(%q<text-hyphen>, [">= 1.0.0"])
|
|
40
|
+
s.add_dependency(%q<hoe>, [">= 1.11.0"])
|
|
41
|
+
end
|
|
42
|
+
end
|
data/History.txt
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
=== 1.0.6 / 2009-12-22
|
|
2
|
+
|
|
3
|
+
* Added Array#average, Die.roll, Float::INFINITY, Time#at_midnight
|
|
4
|
+
* Updated to use Hoe 2.0.
|
|
5
|
+
|
|
6
|
+
=== 1.0.5 / 2009-07-27
|
|
7
|
+
|
|
8
|
+
* Added Hash#map_keys, Hash#map_values, and Hash#map_pairs.
|
|
9
|
+
|
|
10
|
+
=== 1.0.4 / 2009-03-20
|
|
11
|
+
|
|
12
|
+
* Fixed the 'rcov' Rake task so it worked with the latest Hoe.
|
|
13
|
+
* Added a bit of documentation that was missing.
|
|
14
|
+
|
|
15
|
+
=== 1.0.3 / 2008-11-11
|
|
16
|
+
|
|
17
|
+
* Bug fix for a hang in TextFormatter.hyphenate_word, when given a wprd that contains multiple hyphens.
|
|
18
|
+
|
|
19
|
+
=== 1.0.2 / 2008-09-29
|
|
20
|
+
|
|
21
|
+
* Made TextFormatter.split_long_words take a fourth optional argument to control insertion of newlines in split text.
|
|
22
|
+
|
|
23
|
+
=== 1.0.1 / 2008-08-30
|
|
24
|
+
|
|
25
|
+
* Changed the output of ArgChecks.arg_type so that it includes the to_s representation of the object itself in the exception message.
|
|
26
|
+
* Added ArgChecks.arg_responds_to.
|
|
27
|
+
|
|
28
|
+
=== 1.0.0 / 2008-08-04
|
|
29
|
+
|
|
30
|
+
* First release.
|
|
31
|
+
|
|
32
|
+
* Birthday!
|
data/Manifest.txt
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
AvantiConveniences.gemspec
|
|
2
|
+
History.txt
|
|
3
|
+
Manifest.txt
|
|
4
|
+
README.txt
|
|
5
|
+
Rakefile
|
|
6
|
+
lib/arg_checks.rb
|
|
7
|
+
lib/array_extensions.rb
|
|
8
|
+
lib/avanti_conveniences.rb
|
|
9
|
+
lib/die.rb
|
|
10
|
+
lib/float_extensions.rb
|
|
11
|
+
lib/hash_extensions.rb
|
|
12
|
+
lib/string_extensions.rb
|
|
13
|
+
lib/text_formatter.rb
|
|
14
|
+
lib/time_extensions.rb
|
|
15
|
+
lib/uri_extensions.rb
|
|
16
|
+
test/test_arg_checks.rb
|
|
17
|
+
test/test_array_extensions.rb
|
|
18
|
+
test/test_avanti_conveniences.rb
|
|
19
|
+
test/test_die.rb
|
|
20
|
+
test/test_float_extensions.rb
|
|
21
|
+
test/test_hash_extensions.rb
|
|
22
|
+
test/test_string_extensions.rb
|
|
23
|
+
test/test_text_formatter.rb
|
|
24
|
+
test/test_time_extensions.rb
|
|
25
|
+
test/test_uri_extensions.rb
|
|
26
|
+
|
data/README.txt
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
= AvantiConveniences
|
|
2
|
+
|
|
3
|
+
http://www.pervasivecode.com/blog/avanticonveniences/
|
|
4
|
+
Author: Jamie Flournoy (jamie@pervasivecode.com)
|
|
5
|
+
|
|
6
|
+
== DESCRIPTION:
|
|
7
|
+
|
|
8
|
+
AvantiConveniences is a set of convenience code for Ruby on Rails applications.
|
|
9
|
+
|
|
10
|
+
== FEATURES/PROBLEMS:
|
|
11
|
+
|
|
12
|
+
ArgChecks helps you implement simple sanity-checking of arguments, like
|
|
13
|
+
permanent assertions or a poor man's Design by Contract facility, so you can
|
|
14
|
+
write code that will Fail Fast (see http://c2.com/cgi/wiki?FailFast).
|
|
15
|
+
|
|
16
|
+
ArrayExtensions adds Array#average.
|
|
17
|
+
|
|
18
|
+
Die adds Die.roll which is semantic sugar around rand(n).
|
|
19
|
+
|
|
20
|
+
FloatExtensions adds Float::INFINITY, which is semantic sugar for people
|
|
21
|
+
who don't want to see '1.0 / 0' in your code.
|
|
22
|
+
|
|
23
|
+
HashExtensions adds a few methods that help you easily replace all the keys
|
|
24
|
+
and/or values at once.
|
|
25
|
+
|
|
26
|
+
StringExtensions provides String quoting (not escaping) with single quotes,
|
|
27
|
+
double quotes, or a caller-specified quoting character, and a String#dehumanize
|
|
28
|
+
method to do the reverse of the String#humanize method provided by ActiveSupport.
|
|
29
|
+
|
|
30
|
+
TextFormatter provides methods for hyphenating words for word-wrapping.
|
|
31
|
+
|
|
32
|
+
TimeExtensions provides Time#at_midnight, which is useful if you want to work
|
|
33
|
+
with a lot of timestamps that need to be bucketed by day.
|
|
34
|
+
|
|
35
|
+
URIExtensions provides URI::Generic#query_from_hash, which will create a URI
|
|
36
|
+
query string from a Hash.
|
|
37
|
+
|
|
38
|
+
== SYNOPSIS:
|
|
39
|
+
|
|
40
|
+
See individual classes for details. All of them are single method invocations
|
|
41
|
+
that are very simple to use. For additional examples look in the test/
|
|
42
|
+
directory.
|
|
43
|
+
|
|
44
|
+
== REQUIREMENTS:
|
|
45
|
+
|
|
46
|
+
Ruby 1.8.5 (might work with earlier versions), ActiveSupport 1.2.6, Text-Hyphen
|
|
47
|
+
1.0.0, and Hoe 1.7.0.
|
|
48
|
+
|
|
49
|
+
== INSTALL:
|
|
50
|
+
|
|
51
|
+
If you haven't done this before:
|
|
52
|
+
gem sources -a http://gems.github.com
|
|
53
|
+
|
|
54
|
+
Then:
|
|
55
|
+
sudo gem install JamieFlournoy-AvantiConveniences
|
|
56
|
+
|
|
57
|
+
== LICENSE:
|
|
58
|
+
|
|
59
|
+
(The MIT License)
|
|
60
|
+
|
|
61
|
+
Copyright (c) 2008 Pervasive Code
|
|
62
|
+
|
|
63
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
64
|
+
a copy of this software and associated documentation files (the
|
|
65
|
+
'Software'), to deal in the Software without restriction, including
|
|
66
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
67
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
68
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
69
|
+
the following conditions:
|
|
70
|
+
|
|
71
|
+
The above copyright notice and this permission notice shall be
|
|
72
|
+
included in all copies or substantial portions of the Software.
|
|
73
|
+
|
|
74
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
75
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
76
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
77
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
78
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
79
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
80
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# -*- ruby -*-
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'hoe'
|
|
5
|
+
|
|
6
|
+
# Hoe::plugin :gemcutter
|
|
7
|
+
|
|
8
|
+
hoe = Hoe.spec 'AvantiConveniences' do
|
|
9
|
+
developer('Jamie Flournoy', 'jamie@pervasivecode.com')
|
|
10
|
+
extra_deps << ['activesupport', '>= 1.2.6']
|
|
11
|
+
extra_deps << ['text-hyphen', '>= 1.0.0']
|
|
12
|
+
extra_dev_deps << ['thoughtbot-shoulda', '>= 2.10.1']
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
task :gemspec do
|
|
16
|
+
File.open("#{hoe.name}.gemspec", "w") {|f| f << hoe.spec.to_ruby }
|
|
17
|
+
end
|
|
18
|
+
task :package => :gemspec
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# The rcov task in this file worked until Hoe was updated; this code keeps the old behavior
|
|
22
|
+
# and disables Hoe's rcov task.
|
|
23
|
+
Rake::TaskManager.class_eval do
|
|
24
|
+
def remove_task(task_name)
|
|
25
|
+
@tasks.delete(task_name.to_s)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
def remove_task(task_name)
|
|
29
|
+
Rake.application.remove_task(task_name)
|
|
30
|
+
end
|
|
31
|
+
remove_task 'rcov'
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
task :rcov do
|
|
35
|
+
sh 'rcov test/test_*.rb'
|
|
36
|
+
end
|
|
37
|
+
task :clean_rcov do
|
|
38
|
+
sh 'rm -rf ./coverage/*'
|
|
39
|
+
end
|
|
40
|
+
task :clean => [:clean_rcov]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# vim: syntax=Ruby
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# stats
|
|
47
|
+
begin
|
|
48
|
+
gem 'rails'
|
|
49
|
+
require 'code_statistics'
|
|
50
|
+
namespace :spec do
|
|
51
|
+
desc "Use Rails's rake:stats task for a gem"
|
|
52
|
+
task :statsetup do
|
|
53
|
+
class CodeStatistics
|
|
54
|
+
def calculate_statistics
|
|
55
|
+
@pairs.inject({}) do |stats, pair|
|
|
56
|
+
if 3 == pair.size
|
|
57
|
+
stats[pair.first] = calculate_directory_statistics(pair[1], pair[2]); stats
|
|
58
|
+
else
|
|
59
|
+
stats[pair.first] = calculate_directory_statistics(pair.last); stats
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
::STATS_DIRECTORIES = [['Libraries', 'lib', /\.(sql|rhtml|erb|rb|yml)$/],
|
|
65
|
+
['Tests', 'test', /\.(sql|rhtml|erb|rb|yml)$/]]
|
|
66
|
+
::CodeStatistics::TEST_TYPES << "Tests"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
desc "Report code statistics (KLOCs, etc) from the application"
|
|
70
|
+
task :stats => "spec:statsetup" do
|
|
71
|
+
CodeStatistics.new(*STATS_DIRECTORIES).to_s
|
|
72
|
+
end
|
|
73
|
+
rescue Gem::LoadError => le
|
|
74
|
+
task :stats do
|
|
75
|
+
raise RuntimeError, "'rails' gem not found - you must install it in order to use this task.\n"
|
|
76
|
+
end
|
|
77
|
+
end
|
data/lib/arg_checks.rb
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Include this module in your classes that need sanity checking of method arguments.
|
|
2
|
+
# If any of these checks is not satisfied, it will raise an ArgumentError with a
|
|
3
|
+
# detailed message about what went wrong.
|
|
4
|
+
module ArgChecks
|
|
5
|
+
# Require that all arguments be of the specified class, or one of its subclasses (uses is_a?).
|
|
6
|
+
# Consider using arg_responds_to? or respond_to? instead, to make your API more flexible.
|
|
7
|
+
def arg_type(klass, *args)
|
|
8
|
+
raise ArgumentError, "First argument must be a class. Got #{klass.to_s}" unless klass.is_a? Class
|
|
9
|
+
args.each{|obj| raise ArgumentError, "Wrong type for argument '#{obj}' (should be #{klass})" unless obj.is_a? klass }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Require that all arguments respond_to? the specified method.
|
|
13
|
+
def arg_responds_to(method, *args)
|
|
14
|
+
arg_type Symbol, method
|
|
15
|
+
args.each{|obj| raise ArgumentError, "Object #{obj} (class #{obj.class}) doesn't respond to #{method}." unless obj.respond_to? method}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Require that all arguments be non-nil.
|
|
19
|
+
def arg_required(*args)
|
|
20
|
+
args.each{|obj| raise ArgumentError, "Argument cannot be nil" if obj.nil? }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Require that the second argument be non-nil. Upon failure the first argument is used in the error message.
|
|
24
|
+
def named_arg_required(name, obj)
|
|
25
|
+
named_arg_required('name', name) unless name.eql?('name')
|
|
26
|
+
raise ArgumentError, "Argument \"#{name}\" cannot be nil" if obj.nil?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Require that all values in the hash be non-nil. Returns the list of all keys whose values were nil.
|
|
30
|
+
def named_args_required(obj_hash)
|
|
31
|
+
keys_with_nil_values = obj_hash.select{|k,v| v.nil?}.collect{|e| e[0]}
|
|
32
|
+
raise ArgumentError, "Nil argument not allowed in #{keys_with_nil_values.join(', ')}" unless keys_with_nil_values.empty?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Require that all arguments be greater than or equal to max.
|
|
36
|
+
def arg_max(max, *args)
|
|
37
|
+
args.each{|obj| raise ArgumentError, "Argument exceeds maxmimum value (max is #{max.to_s})" unless max >= obj}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Require that all arguments be less than or equal to min.
|
|
41
|
+
def arg_min(min, *args)
|
|
42
|
+
args.each{|obj| raise ArgumentError, "Argument is lower than minimum value (min is #{min.to_s})" unless min <= obj }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Require that all arguments return a set of keys containing at least the specified elements.
|
|
46
|
+
def arg_hash_keys_required(required_keys, *args)
|
|
47
|
+
args.each do |h|
|
|
48
|
+
missing = required_keys - h.keys
|
|
49
|
+
raise ArgumentError, "Hash is missing required keys (#{missing.join(', ')}). Got:\n#{h.inspect}" if missing.length > 0
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Require that all arguments return a set of keys containing exactly the specified elements.
|
|
54
|
+
def arg_hash_keys_exact(exact_keys, *args)
|
|
55
|
+
args.each do |h|
|
|
56
|
+
missing = exact_keys - h.keys
|
|
57
|
+
extra = h.keys - exact_keys
|
|
58
|
+
raise ArgumentError, "Hash keys don't match required set (#{exact_keys.join(', ')}). " +
|
|
59
|
+
"Missing required keys (#{missing.join(', ')}); extra keys not allowed (#{extra.join(', ')}).\n" +
|
|
60
|
+
"Got:\n#{h.inspect}" if (missing.length > 0) || (extra.length >0)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Require that all arguments return a set of keys containing a set of required keys, zero or more of the optional keys, and nothing else.
|
|
65
|
+
def arg_hash_keys_limit(required_keys, optional_keys, *args)
|
|
66
|
+
args.each do |h|
|
|
67
|
+
missing = required_keys - h.keys
|
|
68
|
+
extra = h.keys - required_keys - optional_keys
|
|
69
|
+
|
|
70
|
+
unless missing.empty? && extra.empty?
|
|
71
|
+
msg = ""
|
|
72
|
+
msg << "Hash is missing required keys (#{missing.join(', ')}).\n" unless missing.empty?
|
|
73
|
+
msg << "Hash has extra keys which aren't allowed (#{extra.join(', ')}).\n" unless extra.empty?
|
|
74
|
+
msg << " Got: #{h.inspect}"
|
|
75
|
+
raise ArgumentError, msg
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/arg_checks'
|
|
2
|
+
require File.dirname(__FILE__) + '/array_extensions'
|
|
3
|
+
require File.dirname(__FILE__) + '/die'
|
|
4
|
+
require File.dirname(__FILE__) + '/float_extensions'
|
|
5
|
+
require File.dirname(__FILE__) + '/hash_extensions'
|
|
6
|
+
require File.dirname(__FILE__) + '/string_extensions'
|
|
7
|
+
require File.dirname(__FILE__) + '/text_formatter'
|
|
8
|
+
require File.dirname(__FILE__) + '/time_extensions'
|
|
9
|
+
require File.dirname(__FILE__) + '/uri_extensions'
|
|
10
|
+
|
|
11
|
+
class AvantiConveniences
|
|
12
|
+
VERSION = '1.0.6'
|
|
13
|
+
end
|
data/lib/die.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class Hash
|
|
2
|
+
# Call a block for every key in the Hash, and replace each key with the block's return value.
|
|
3
|
+
# This returns a new Hash, so you do not need to call #rehash on it.
|
|
4
|
+
def map_keys(&block)
|
|
5
|
+
Hash[* self.to_a.map{|k,v| [yield(k), v] }.flatten ]
|
|
6
|
+
end
|
|
7
|
+
alias_method :rekey, :map_keys unless Hash.new.respond_to? :rekey
|
|
8
|
+
|
|
9
|
+
# Call a block for every value in the Hash, and replace each value with the block's return value.
|
|
10
|
+
def map_values(&block)
|
|
11
|
+
Hash[* self.to_a.map{|k,v| [k, yield(v)] }.flatten ]
|
|
12
|
+
end
|
|
13
|
+
alias_method :revalue, :map_keys unless Hash.new.respond_to? :revalue
|
|
14
|
+
|
|
15
|
+
# Call a block for every (key, value) pair in the hash, passing them in as a 2-element Array.
|
|
16
|
+
# The block should return a similar 2-element array of (key, value) which will be used to replace
|
|
17
|
+
# the original key and value.
|
|
18
|
+
def map_pairs(&block)
|
|
19
|
+
Hash[* self.to_a.map{|k,v| yield(k,v) }.flatten ]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
gem 'activesupport', '>= 1.2.6'
|
|
3
|
+
require 'active_support' # for titleize
|
|
4
|
+
|
|
5
|
+
class String
|
|
6
|
+
# Convert a string consisting of whitespace separated words into an underscore-delimited
|
|
7
|
+
# set of lowercase words. This is the opposite of what ActiveSupport's String.humanize
|
|
8
|
+
# method docs.
|
|
9
|
+
# Example: 'Foo Bar' -> 'foo_bar'
|
|
10
|
+
def dehumanize
|
|
11
|
+
titleize.gsub(/\W+/,'_').gsub(/\s+/,'_').gsub(/^_+|_+$/,'').underscore
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Return this string, surrounded by quote_char on either side.
|
|
15
|
+
def quote(quote_char)
|
|
16
|
+
"#{quote_char}#{self}#{quote_char}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Return this string, surrounded by a single quote (') on either side.
|
|
20
|
+
def single_quote; self.quote("'"); end
|
|
21
|
+
|
|
22
|
+
# Return this string, surrounded by a double quote (") on either side.
|
|
23
|
+
def double_quote; self.quote('"'); end
|
|
24
|
+
|
|
25
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
|
|
3
|
+
# Note: Text::Hyphen 1.0.0 uses attr_accessor in a couple of places
|
|
4
|
+
# where it should use attr_reader, because a setter is defined
|
|
5
|
+
# immediately afterward; this causes 'method redefined' warnings
|
|
6
|
+
# when running 'rake test' since the Hoe gem enables the ruby -w flag.
|
|
7
|
+
# To fix this warning, Text::Hyphen must be fixed. so...
|
|
8
|
+
# TODO patch Text::Hyphen to fix the 'method redefined' warnings.
|
|
9
|
+
gem 'text-hyphen', '>= 1.0.0'
|
|
10
|
+
require 'text/hyphen'
|
|
11
|
+
|
|
12
|
+
# Several methods take a language_code argument. This is the language code
|
|
13
|
+
# (like 'en_us') required by Text::Hyphen.
|
|
14
|
+
class TextFormatter
|
|
15
|
+
# Replace all words longer than max_width with the results of split_word.
|
|
16
|
+
# Leading and trailing whitespace is eliminated and inline whitespace runs are replaced with a space.
|
|
17
|
+
def split_long_words(string, max_width, language_code, append_newlines = false)
|
|
18
|
+
words = string.split
|
|
19
|
+
words.collect{|w| w.length > max_width ? split_word(w, max_width, language_code, append_newlines) : w}.flatten.join(' ')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Split one word and return it as an array of substrings no longer than the specified size.
|
|
23
|
+
# Splitting results consist of a hyphenated version (if possible) or by cutting the word into
|
|
24
|
+
# segments no longer than max_width (if hyphenation fails, such as for the word 'xxxxxxxxxxx')
|
|
25
|
+
# Every substring except the last will have a newline appended unless append_newlines is false.
|
|
26
|
+
# The result for a 'word' string containing whitespace is undefined.
|
|
27
|
+
def split_word(word, size, langauge_code, append_newlines = true)
|
|
28
|
+
hyphenated = hyphenate_word(word,size,langauge_code)
|
|
29
|
+
hyphenated_chopped = hyphenated.collect{|w| w.length > size ? chop_word(w, size) : w}.flatten
|
|
30
|
+
if append_newlines
|
|
31
|
+
hyphenated_chopped.collect!{|w| "#{w}\n"}
|
|
32
|
+
hyphenated_chopped.last.chop!
|
|
33
|
+
end
|
|
34
|
+
return hyphenated_chopped
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Try to hyphenate a word into chunks just barely short enough to fit within the specified size
|
|
38
|
+
def hyphenate_word(word, size, language_code)
|
|
39
|
+
# handle pre-hyphenated words, which hyphenate_to balks on
|
|
40
|
+
hyphenated = word.split(/-/)
|
|
41
|
+
if hyphenated.size > 1
|
|
42
|
+
hyphenated.collect!{|w| w.length > size ? self.hyphenate_word(w, size, language_code) : w}
|
|
43
|
+
hyphenated.flatten!
|
|
44
|
+
last = hyphenated.pop
|
|
45
|
+
hyphenated.collect!{|w| w[-1,1].eql?('-') ? w : "#{w}-"}
|
|
46
|
+
hyphenated.push(last)
|
|
47
|
+
return hyphenated
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
h = TextFormatter.text_hyphenator(language_code)
|
|
51
|
+
hyphenated = h.hyphenate_to(word, size).compact
|
|
52
|
+
|
|
53
|
+
loop_limit = word.length
|
|
54
|
+
while (hyphenated.size > 1 && hyphenated.last.length > size) do
|
|
55
|
+
last = hyphenated.pop
|
|
56
|
+
part1, part2 = h.hyphenate_to(last, size).compact
|
|
57
|
+
hyphenated.push(part1)
|
|
58
|
+
hyphenated.push(part2) unless part2.nil?
|
|
59
|
+
|
|
60
|
+
loop_limit -= 1
|
|
61
|
+
break if last.eql?(part1) || (loop_limit < 0)
|
|
62
|
+
end
|
|
63
|
+
return hyphenated
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Simply chop overly long "words" into chunks no longer than the specified size
|
|
67
|
+
def chop_word(word, size)
|
|
68
|
+
chopped = []
|
|
69
|
+
while (!word.nil? && word.length > size) do
|
|
70
|
+
chopped.push word[0,size]
|
|
71
|
+
word = word[size..-1]
|
|
72
|
+
end
|
|
73
|
+
chopped.push(word) # get the last chunk
|
|
74
|
+
return chopped
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Get a Text::Hyphen instance for a specified language
|
|
78
|
+
def TextFormatter.text_hyphenator(language_code)
|
|
79
|
+
@@hyphenators = Hash.new unless defined? @@hyphenators
|
|
80
|
+
@@hyphenators[language_code] ||= Text::Hyphen.new(:language => language_code, :left => 2, :right => 2)
|
|
81
|
+
return @@hyphenators[language_code]
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
gem 'activesupport'
|
|
3
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
|
4
|
+
|
|
5
|
+
require 'uri'
|
|
6
|
+
require File.dirname(__FILE__) + '/hash_extensions'
|
|
7
|
+
|
|
8
|
+
class URI::Generic
|
|
9
|
+
# Create a URI query string from a Hash. The keys in the returned query string
|
|
10
|
+
# are sorted for easier testing.
|
|
11
|
+
# Example: {:foo => 'bar', :biz => 'b a z'} -> '?biz=b%20a%20z&foo=bar'
|
|
12
|
+
def self.query_from_hash(q_hash)
|
|
13
|
+
return '' if q_hash.nil?
|
|
14
|
+
|
|
15
|
+
# Reveal cases where the caller thought they were using HashWithIndifferentAccess
|
|
16
|
+
# but actually they used Hash and probably got duplicate keys (:foo vs 'foo')
|
|
17
|
+
q_hash = q_hash.rekey{|k| k.is_a?(Symbol) ? ":#{k}" : k} unless q_hash.is_a?(HashWithIndifferentAccess)
|
|
18
|
+
|
|
19
|
+
pairs = []
|
|
20
|
+
q_hash.each_pair{|k,v| pairs << "#{k}=#{URI.escape(v.to_s)}" unless v.nil?}
|
|
21
|
+
'?' + pairs.sort.join('&')
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require File.dirname(__FILE__) + '/../lib/arg_checks'
|
|
3
|
+
|
|
4
|
+
class TestArgChecks < Test::Unit::TestCase
|
|
5
|
+
include ArgChecks
|
|
6
|
+
|
|
7
|
+
def test_arg_type
|
|
8
|
+
assert_nothing_raised(ArgumentError) { arg_dummy('s', 3.0) }
|
|
9
|
+
assert_raise(ArgumentError) { arg_dummy('s', 3) }
|
|
10
|
+
assert_raise(ArgumentError) { arg_dummy('blah blah', 'x') }
|
|
11
|
+
assert_raise(ArgumentError) { arg_dummy(3.0, 3.0) }
|
|
12
|
+
|
|
13
|
+
assert_nothing_raised(ArgumentError) { arg_dummy2('s', -1.0, 10.0, 'x') }
|
|
14
|
+
assert_raise(ArgumentError) { arg_dummy2(-1.0, 10.0, 'x', 'blah') }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_arg_required
|
|
18
|
+
assert_raise(ArgumentError) { arg_dummy5(nil, nil) }
|
|
19
|
+
assert_raise(ArgumentError) { arg_dummy5(nil, 3.0) }
|
|
20
|
+
assert_raise(ArgumentError) { arg_dummy5('blah', nil) }
|
|
21
|
+
assert_nothing_raised(ArgumentError) { arg_dummy5('blah', 3.0) }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def arg_dummy5(arg1, arg2)
|
|
25
|
+
arg_required arg1, arg2
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def arg_dummy(arg1_string, arg2_float)
|
|
29
|
+
arg_type String, arg1_string
|
|
30
|
+
arg_type Float, arg2_float
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def arg_dummy2(arg1_string, arg2_float, arg3_float, arg4_string)
|
|
34
|
+
arg_type String, arg1_string, arg4_string
|
|
35
|
+
arg_type Float, arg2_float, arg3_float
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_arg_min
|
|
39
|
+
assert_raise(ArgumentError) {arg_dummy3(5, 'z')}
|
|
40
|
+
assert_raise(ArgumentError) {arg_dummy3(100, 'x')}
|
|
41
|
+
assert_nothing_raised(ArgumentError) {arg_dummy3(100, 'z')}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def arg_dummy3(arg1, arg2)
|
|
45
|
+
arg_min 6, arg1
|
|
46
|
+
arg_min 'y', arg2
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_arg_max
|
|
50
|
+
assert_raise(ArgumentError) {arg_dummy4(100, 'z')}
|
|
51
|
+
assert_raise(ArgumentError) {arg_dummy4(5, 'z')}
|
|
52
|
+
assert_nothing_raised(ArgumentError) {arg_dummy4(5, 'x')}
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def arg_dummy4(arg1, arg2)
|
|
56
|
+
arg_max 6, arg1
|
|
57
|
+
arg_max 'y', arg2
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
@@hash = {'k1' => 'v1', 'k2'=>'v2'}
|
|
61
|
+
|
|
62
|
+
def test_arg_hash_keys_exact
|
|
63
|
+
assert_nothing_raised(ArgumentError) { arg_hash_keys_exact %w{k1 k2}, @@hash }
|
|
64
|
+
|
|
65
|
+
assert_raise(ArgumentError) { arg_hash_keys_exact %w{k1}, @@hash}
|
|
66
|
+
assert_raise(ArgumentError) { arg_hash_keys_exact %w{k2}, @@hash }
|
|
67
|
+
assert_raise(ArgumentError) { arg_hash_keys_exact %w{k1 k2 k3}, @@hash }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_arg_hash_keys_required
|
|
71
|
+
assert_nothing_raised(ArgumentError) { arg_hash_keys_required %w{k1 k2}, @@hash }
|
|
72
|
+
assert_nothing_raised(ArgumentError) { arg_hash_keys_required %w{k1}, @@hash }
|
|
73
|
+
assert_nothing_raised(ArgumentError) { arg_hash_keys_required %w{k2}, @@hash }
|
|
74
|
+
|
|
75
|
+
assert_raise(ArgumentError) { arg_hash_keys_required %w{k1 k2 k3}, @@hash }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_arg_hash_keys_limit
|
|
79
|
+
assert_nothing_raised(ArgumentError) { arg_hash_keys_limit %w{k1 k2}, %w{k3}, @@hash }
|
|
80
|
+
assert_nothing_raised(ArgumentError) { arg_hash_keys_limit %w{k1}, %w{k2 k3}, @@hash }
|
|
81
|
+
assert_nothing_raised(ArgumentError) { arg_hash_keys_limit %w{k2}, %w{k1 k3}, @@hash }
|
|
82
|
+
assert_nothing_raised(ArgumentError) { arg_hash_keys_limit [], %w{k1 k2 k3}, @@hash }
|
|
83
|
+
|
|
84
|
+
assert_raise(ArgumentError) { arg_hash_keys_limit %w{k1 k2 k3}, [], @@hash }
|
|
85
|
+
assert_raise(ArgumentError) { arg_hash_keys_limit %w{k1 k3}, %w{k2}, @@hash }
|
|
86
|
+
assert_raise(ArgumentError) { arg_hash_keys_limit %w{k3}, %w{k1, k2}, @@hash }
|
|
87
|
+
assert_raise(ArgumentError) { arg_hash_keys_limit [], [], @@hash }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def test_named_arg_required
|
|
91
|
+
assert_nothing_raised(ArgumentError){ named_arg_required('foo', 1) }
|
|
92
|
+
assert_raise(ArgumentError){ named_arg_required('bar', nil) }
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def test_named_args_required
|
|
96
|
+
assert_nothing_raised(ArgumentError){ named_args_required({}) }
|
|
97
|
+
assert_nothing_raised(ArgumentError){ named_args_required(:foo => 1) }
|
|
98
|
+
assert_raise(ArgumentError){ named_args_required(:bar => nil) }
|
|
99
|
+
assert_raise(ArgumentError){ named_args_required(:foo => 1, :bar => nil) }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def test_arg_respond_to
|
|
103
|
+
assert_nothing_raised(ArgumentError) { arg_dummy6(:round, 1.1) }
|
|
104
|
+
assert_nothing_raised(ArgumentError) { arg_dummy6(:round, Float::EPSILON) }
|
|
105
|
+
assert_raise(ArgumentError) { arg_dummy6(:round, 'a') }
|
|
106
|
+
assert_raise(ArgumentError) { arg_dummy6(:round, [0]) }
|
|
107
|
+
assert_raise(ArgumentError) { arg_dummy6(:round, Object) }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def arg_dummy6(arg1, arg2)
|
|
111
|
+
arg_responds_to arg1, arg2
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require File.dirname(__FILE__) + '/../lib/array_extensions'
|
|
3
|
+
require 'shoulda'
|
|
4
|
+
|
|
5
|
+
module StringMath
|
|
6
|
+
def +(other)
|
|
7
|
+
result = super(other)
|
|
8
|
+
result.extend StringMath
|
|
9
|
+
result
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def /(denominator)
|
|
13
|
+
chunk_size = (self.size.to_f / denominator).to_i
|
|
14
|
+
self[0..(chunk_size - 1)]
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestArrayExtensions < Test::Unit::TestCase
|
|
20
|
+
|
|
21
|
+
context 'Array.average' do
|
|
22
|
+
should 'return the average of 3 integers' do
|
|
23
|
+
assert_equal 5, [1,3,11].average
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
should 'return the average of 3 floats' do
|
|
27
|
+
assert_equal 5.21, [1.1, 3.3, 11.23].average
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
should 'work on anything that supports + and / operators' do
|
|
31
|
+
test_data = [1,3,11].map{|n| ('x' * n).extend StringMath}
|
|
32
|
+
assert_equal 'xxxxx', test_data.average
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
data/test/test_die.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require File.dirname(__FILE__) + '/../lib/die'
|
|
3
|
+
require 'shoulda'
|
|
4
|
+
|
|
5
|
+
class TestDie < Test::Unit::TestCase
|
|
6
|
+
|
|
7
|
+
context 'Die.roll' do
|
|
8
|
+
setup do
|
|
9
|
+
seed = 1234567890
|
|
10
|
+
srand(seed)
|
|
11
|
+
@expected_rand = rand
|
|
12
|
+
srand(seed)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
should 'return a value between 1 and the number of sides' do
|
|
16
|
+
sides = 1000
|
|
17
|
+
expected = (@expected_rand * sides + 1).to_i
|
|
18
|
+
assert_equal expected, Die.roll(sides)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require File.dirname(__FILE__) + '/../lib/float_extensions'
|
|
3
|
+
require 'shoulda'
|
|
4
|
+
|
|
5
|
+
class TestFloatExtensions < Test::Unit::TestCase
|
|
6
|
+
|
|
7
|
+
context 'Float::INFINITY' do
|
|
8
|
+
should 'be greater than 10**100' do
|
|
9
|
+
assert Float::INFINITY > 10**100
|
|
10
|
+
end
|
|
11
|
+
should 'be equal to the absolute value of negative infinity' do
|
|
12
|
+
negative_infinity = -1.0 / 0
|
|
13
|
+
assert_equal negative_infinity.abs, Float::INFINITY
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require File.dirname(__FILE__) + '/../lib/hash_extensions'
|
|
3
|
+
|
|
4
|
+
class TestHashExtensions < Test::Unit::TestCase
|
|
5
|
+
def test_map_keys
|
|
6
|
+
expected = {10 => :a, 20 => :b}
|
|
7
|
+
actual = {1 => :a, 2 => :b}.map_keys{|k| k * 10}
|
|
8
|
+
assert_equal expected, actual
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_map_values
|
|
12
|
+
expected = {:a => 10, :b => 20}
|
|
13
|
+
actual = {:a => 1, :b => 2}.map_values{|k| k * 10}
|
|
14
|
+
assert_equal expected, actual
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_map_pairs
|
|
18
|
+
expected = {'A' => 10, 'B' => 20}
|
|
19
|
+
actual = {'a' => 1, 'b' => 2}.map_pairs{|k, v| [k.upcase, v * 10] }
|
|
20
|
+
assert_equal expected, actual
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require File.dirname(__FILE__) + '/../lib/string_extensions'
|
|
3
|
+
require 'shoulda'
|
|
4
|
+
|
|
5
|
+
gem 'activesupport', '>= 1.2.6'
|
|
6
|
+
require 'active_support' # for .humanize
|
|
7
|
+
|
|
8
|
+
class TestStringExtensions < Test::Unit::TestCase
|
|
9
|
+
context 'String#dehumanize' do
|
|
10
|
+
[ ['Hello, World', 'hello_world'],
|
|
11
|
+
['$$$123#456', '123_456'],
|
|
12
|
+
['a_b_c_', 'a_b_c'],
|
|
13
|
+
['/etc/passwd', 'etc_passwd'],
|
|
14
|
+
['Foo', 'foo'],
|
|
15
|
+
['Foo Bar', 'foo_bar'],
|
|
16
|
+
['Foo_Bar', 'foo_bar'],
|
|
17
|
+
["foo\tbar\nbiz \t\n\t \n\t\n baz_ ", 'foo_bar_biz_baz'],
|
|
18
|
+
].each do |input, expected|
|
|
19
|
+
should("convert #{input} into #{expected}") do
|
|
20
|
+
assert_equal expected, input.dehumanize
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
%w{1 x hello_world 123_456 foo_bar}.each do |round_trippable|
|
|
25
|
+
should "undo humanize(#{round_trippable})" do
|
|
26
|
+
assert_equal round_trippable, round_trippable.humanize.dehumanize
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
['1', 'X', 'A herring', 'Hello world'].each do |rehumanizable|
|
|
31
|
+
should "return a value for #{rehumanizable} that humanize can undo correctly" do
|
|
32
|
+
assert_equal rehumanizable, rehumanizable.dehumanize.humanize
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_quote
|
|
41
|
+
d = {'Foo' => '~Foo~',
|
|
42
|
+
'Foo~' => '~Foo~~',
|
|
43
|
+
'Foo Bar' => '~Foo Bar~'}
|
|
44
|
+
d.each{|i,o| assert_equal o, i.quote('~')}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_single_quote
|
|
48
|
+
d = {'Foo Bar' => "'Foo Bar'"}
|
|
49
|
+
d.each{|i,o| assert_equal o, i.single_quote}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test_double_quote
|
|
53
|
+
d = {'Foo Bar' => '"Foo Bar"'}
|
|
54
|
+
d.each{|i,o| assert_equal o, i.double_quote}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require File.dirname(__FILE__) + '/../lib/text_formatter'
|
|
3
|
+
|
|
4
|
+
class TestTextFormatter < Test::Unit::TestCase
|
|
5
|
+
def setup
|
|
6
|
+
@tf = TextFormatter.new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_chop_word_1
|
|
10
|
+
assert_equal %w{xxx xxx xxx x}, @tf.chop_word('xxxxxxxxxx', 3)
|
|
11
|
+
end
|
|
12
|
+
def test_chop_word_2
|
|
13
|
+
assert_equal %w{xxx xx}, @tf.chop_word('xxxxx', 3)
|
|
14
|
+
end
|
|
15
|
+
def test_chop_word_3
|
|
16
|
+
assert_equal %w{xx}, @tf.chop_word('xx', 3)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_hyphenate_word_1
|
|
20
|
+
assert_equal ["Hobo-", 'ken'], @tf.hyphenate_word('Hoboken',5,'en_us')
|
|
21
|
+
end
|
|
22
|
+
def test_hyphenate_word_2
|
|
23
|
+
assert_equal ["spectac-", 'ular'], @tf.hyphenate_word('spectacular',8,'en_us')
|
|
24
|
+
end
|
|
25
|
+
def test_hyphenate_word_3
|
|
26
|
+
assert_equal ["antidisestab-","lishmentarian-","ism"], @tf.hyphenate_word('antidisestablishmentarianism', 15, 'en_us')
|
|
27
|
+
end
|
|
28
|
+
def test_hyphenate_word_4
|
|
29
|
+
x = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
|
30
|
+
assert_equal [x], @tf.hyphenate_word(x, 5, 'en_us')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Real words
|
|
34
|
+
def test_split_word_1
|
|
35
|
+
assert_equal ["Hobo-\n", 'ken'], @tf.split_word('Hoboken',5,'en_us')
|
|
36
|
+
end
|
|
37
|
+
def test_split_word_2
|
|
38
|
+
assert_equal ["spectac-\n", 'ular'], @tf.split_word('spectacular',8,'en_us')
|
|
39
|
+
end
|
|
40
|
+
def test_split_word_3
|
|
41
|
+
assert_equal ["spectac-", 'ular'], @tf.split_word('spectacular',8,'en_us', false)
|
|
42
|
+
end
|
|
43
|
+
def test_split_word_4
|
|
44
|
+
assert_equal ["antidisestab-\n","lishmentarian-\n","ism"], @tf.split_word('antidisestablishmentarianism', 15, 'en_us')
|
|
45
|
+
end
|
|
46
|
+
def test_split_word_5
|
|
47
|
+
assert_equal ["antidisestab-","lishmentarian-","ism"], @tf.split_word('antidisestablishmentarianism', 15, 'en_us', false)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# long strings get chopped
|
|
51
|
+
def test_split_word_6
|
|
52
|
+
x = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
|
53
|
+
split_x = []
|
|
54
|
+
15.times{split_x.push("xxxxx\n")}
|
|
55
|
+
split_x.push('x')
|
|
56
|
+
assert_equal split_x, @tf.split_word(x, 5, 'en_us')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# pre-hyphenated words should be easy to handle
|
|
60
|
+
def test_split_word_7
|
|
61
|
+
assert_equal ["prepared-","from-","recipe"], @tf.split_word('prepared-from-recipe', 15, 'en_us', false)
|
|
62
|
+
end
|
|
63
|
+
def test_split_word_8
|
|
64
|
+
assert_equal ["pre-","pared-","from-","recipe"], @tf.split_word('prepared-from-recipe', 6, 'en_us', false)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def test_split_long_words_1
|
|
68
|
+
assert_equal "Hobo- ken", @tf.split_long_words('Hoboken',5,'en_us')
|
|
69
|
+
end
|
|
70
|
+
def test_split_long_words_2
|
|
71
|
+
assert_equal "spectac- ular", @tf.split_long_words('spectacular',8,'en_us')
|
|
72
|
+
end
|
|
73
|
+
def test_split_long_words_3
|
|
74
|
+
assert_equal "antidisestab- lishmentarian- ism", @tf.split_long_words('antidisestablishmentarianism', 15, 'en_us')
|
|
75
|
+
end
|
|
76
|
+
def test_split_long_words_4
|
|
77
|
+
i = ["Hoboken New Jersey \n\n \t is a\t \nnice \n\t\n\t place.",5,'en_us']
|
|
78
|
+
o = "Hobo- ken New Jer- sey is a nice place ."
|
|
79
|
+
assert_equal o, @tf.split_long_words(*i)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require File.dirname(__FILE__) + '/../lib/array_extensions'
|
|
3
|
+
require 'shoulda'
|
|
4
|
+
|
|
5
|
+
gem 'activesupport', '>= 1.2.6'
|
|
6
|
+
require 'active_support' # for .hour, .hours, .second
|
|
7
|
+
|
|
8
|
+
class TestArrayExtensions < Test::Unit::TestCase
|
|
9
|
+
|
|
10
|
+
context 'Time#at_midnight' do
|
|
11
|
+
[ ['2009-12-01 01:00:00', 1.hour ],
|
|
12
|
+
['2009-12-01 00:00:00', 0 ],
|
|
13
|
+
['2009-12-01 23:59:59', (24.hours - 1.second) ],
|
|
14
|
+
].each do |input, expected|
|
|
15
|
+
should "be #{expected} seconds before #{input}" do
|
|
16
|
+
t = Time.parse(input)
|
|
17
|
+
assert_equal expected, t - t.at_midnight
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require File.dirname(__FILE__) + '/../lib/uri_extensions'
|
|
3
|
+
|
|
4
|
+
class TestUriExtensions < Test::Unit::TestCase
|
|
5
|
+
def test_uri_generic_query_from_hash
|
|
6
|
+
assert_equal '?a=1&b=2', URI::Generic.query_from_hash('a'=>1, 'b'=>2)
|
|
7
|
+
assert_equal '?:a=1&a=11&b=2', URI::Generic.query_from_hash(:a=>1, 'b'=>2, 'a'=>11)
|
|
8
|
+
assert_equal '?biz=b%20a%20z&foo=bar', URI::Generic.query_from_hash('foo' => 'bar', 'biz' => 'b a z')
|
|
9
|
+
|
|
10
|
+
h = HashWithIndifferentAccess.new
|
|
11
|
+
h.merge! :a=>1, :b=>2
|
|
12
|
+
assert_equal '?a=1&b=2', URI::Generic.query_from_hash(h)
|
|
13
|
+
end
|
|
14
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: AvantiConveniences
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.6
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Jamie Flournoy
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2009-12-22 00:00:00 -08:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies:
|
|
15
|
+
- !ruby/object:Gem::Dependency
|
|
16
|
+
name: activesupport
|
|
17
|
+
type: :runtime
|
|
18
|
+
version_requirement:
|
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">="
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: 1.2.6
|
|
24
|
+
version:
|
|
25
|
+
- !ruby/object:Gem::Dependency
|
|
26
|
+
name: text-hyphen
|
|
27
|
+
type: :runtime
|
|
28
|
+
version_requirement:
|
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 1.0.0
|
|
34
|
+
version:
|
|
35
|
+
- !ruby/object:Gem::Dependency
|
|
36
|
+
name: thoughtbot-shoulda
|
|
37
|
+
type: :development
|
|
38
|
+
version_requirement:
|
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: 2.10.1
|
|
44
|
+
version:
|
|
45
|
+
- !ruby/object:Gem::Dependency
|
|
46
|
+
name: hoe
|
|
47
|
+
type: :development
|
|
48
|
+
version_requirement:
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: 2.3.3
|
|
54
|
+
version:
|
|
55
|
+
description: AvantiConveniences is a set of convenience code for Ruby on Rails applications.
|
|
56
|
+
email:
|
|
57
|
+
- jamie@pervasivecode.com
|
|
58
|
+
executables: []
|
|
59
|
+
|
|
60
|
+
extensions: []
|
|
61
|
+
|
|
62
|
+
extra_rdoc_files:
|
|
63
|
+
- History.txt
|
|
64
|
+
- Manifest.txt
|
|
65
|
+
- README.txt
|
|
66
|
+
files:
|
|
67
|
+
- AvantiConveniences.gemspec
|
|
68
|
+
- History.txt
|
|
69
|
+
- Manifest.txt
|
|
70
|
+
- README.txt
|
|
71
|
+
- Rakefile
|
|
72
|
+
- lib/arg_checks.rb
|
|
73
|
+
- lib/array_extensions.rb
|
|
74
|
+
- lib/avanti_conveniences.rb
|
|
75
|
+
- lib/die.rb
|
|
76
|
+
- lib/float_extensions.rb
|
|
77
|
+
- lib/hash_extensions.rb
|
|
78
|
+
- lib/string_extensions.rb
|
|
79
|
+
- lib/text_formatter.rb
|
|
80
|
+
- lib/time_extensions.rb
|
|
81
|
+
- lib/uri_extensions.rb
|
|
82
|
+
- test/test_arg_checks.rb
|
|
83
|
+
- test/test_array_extensions.rb
|
|
84
|
+
- test/test_avanti_conveniences.rb
|
|
85
|
+
- test/test_die.rb
|
|
86
|
+
- test/test_float_extensions.rb
|
|
87
|
+
- test/test_hash_extensions.rb
|
|
88
|
+
- test/test_string_extensions.rb
|
|
89
|
+
- test/test_text_formatter.rb
|
|
90
|
+
- test/test_time_extensions.rb
|
|
91
|
+
- test/test_uri_extensions.rb
|
|
92
|
+
has_rdoc: true
|
|
93
|
+
homepage: http://www.pervasivecode.com/blog/avanticonveniences/
|
|
94
|
+
licenses: []
|
|
95
|
+
|
|
96
|
+
post_install_message:
|
|
97
|
+
rdoc_options:
|
|
98
|
+
- --main
|
|
99
|
+
- README.txt
|
|
100
|
+
require_paths:
|
|
101
|
+
- lib
|
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
|
+
requirements:
|
|
104
|
+
- - ">="
|
|
105
|
+
- !ruby/object:Gem::Version
|
|
106
|
+
version: "0"
|
|
107
|
+
version:
|
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
|
+
requirements:
|
|
110
|
+
- - ">="
|
|
111
|
+
- !ruby/object:Gem::Version
|
|
112
|
+
version: "0"
|
|
113
|
+
version:
|
|
114
|
+
requirements: []
|
|
115
|
+
|
|
116
|
+
rubyforge_project: avanticonveniences
|
|
117
|
+
rubygems_version: 1.3.5
|
|
118
|
+
signing_key:
|
|
119
|
+
specification_version: 3
|
|
120
|
+
summary: AvantiConveniences is a set of convenience code for Ruby on Rails applications.
|
|
121
|
+
test_files:
|
|
122
|
+
- test/test_arg_checks.rb
|
|
123
|
+
- test/test_array_extensions.rb
|
|
124
|
+
- test/test_avanti_conveniences.rb
|
|
125
|
+
- test/test_die.rb
|
|
126
|
+
- test/test_float_extensions.rb
|
|
127
|
+
- test/test_hash_extensions.rb
|
|
128
|
+
- test/test_string_extensions.rb
|
|
129
|
+
- test/test_text_formatter.rb
|
|
130
|
+
- test/test_time_extensions.rb
|
|
131
|
+
- test/test_uri_extensions.rb
|