s4t-utils 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. data/LICENSE.txt +34 -0
  2. data/Manifest.txt +52 -0
  3. data/NOTES.txt +7 -0
  4. data/README.txt +2 -0
  5. data/Rakefile +13 -0
  6. data/Rakefile.hoe +22 -0
  7. data/bin/make-s4t-project.rb +159 -0
  8. data/bin/s4t-script-location-file +1 -0
  9. data/data/make-s4t-project/README-skeleton +30 -0
  10. data/data/make-s4t-project/Rakefile.example +32 -0
  11. data/data/make-s4t-project/bin-skeleton +23 -0
  12. data/data/make-s4t-project/main-lib-skeleton +14 -0
  13. data/data/make-s4t-project/set-standalone-test-paths.rb +5 -0
  14. data/data/make-s4t-project/setup.rb +1585 -0
  15. data/data/make-s4t-project/sub-lib-skeleton +3 -0
  16. data/data/make-s4t-project/test-skeleton +28 -0
  17. data/data/make-s4t-project/version-skeleton +3 -0
  18. data/lib/s4t-utils.rb +23 -0
  19. data/lib/s4t-utils/capturing-globals.rb +93 -0
  20. data/lib/s4t-utils/claims.rb +20 -0
  21. data/lib/s4t-utils/command-line.rb +18 -0
  22. data/lib/s4t-utils/error-handling.rb +26 -0
  23. data/lib/s4t-utils/friendly-format.rb +35 -0
  24. data/lib/s4t-utils/hacks.rb +55 -0
  25. data/lib/s4t-utils/load-path-auto-adjuster.rb +120 -0
  26. data/lib/s4t-utils/more-assertions.rb +35 -0
  27. data/lib/s4t-utils/os.rb +28 -0
  28. data/lib/s4t-utils/rake-task-helpers.rb +75 -0
  29. data/lib/s4t-utils/rakefile-common.rb +112 -0
  30. data/lib/s4t-utils/svn-file-movement.rb +104 -0
  31. data/lib/s4t-utils/test-util.rb +19 -0
  32. data/lib/s4t-utils/version.rb +3 -0
  33. data/setup.rb +1585 -0
  34. data/test/capturing-globals-tests.rb +42 -0
  35. data/test/data/make-s4t-project/README-skeleton +30 -0
  36. data/test/data/make-s4t-project/Rakefile.example +32 -0
  37. data/test/data/make-s4t-project/bin-skeleton +23 -0
  38. data/test/data/make-s4t-project/main-lib-skeleton +14 -0
  39. data/test/data/make-s4t-project/set-standalone-test-paths.rb +5 -0
  40. data/test/data/make-s4t-project/setup.rb +1585 -0
  41. data/test/data/make-s4t-project/sub-lib-skeleton +3 -0
  42. data/test/data/make-s4t-project/test-skeleton +28 -0
  43. data/test/data/make-s4t-project/version-skeleton +3 -0
  44. data/test/data/test-data-location-file +1 -0
  45. data/test/error-handling-tests.rb +43 -0
  46. data/test/friendly-format-tests.rb +15 -0
  47. data/test/hacks-tests.rb +42 -0
  48. data/test/load-path-auto-adjuster-tests.rb +88 -0
  49. data/test/rake-task-helper-tests.rb +62 -0
  50. data/test/set-standalone-test-paths.rb +5 -0
  51. data/test/test-location-file +1 -0
  52. data/test/test-util-tests.rb +45 -0
  53. metadata +116 -0
@@ -0,0 +1,3 @@
1
+ module !REPLACE_ME_MODULE!
2
+ # Your code here
3
+ end
@@ -0,0 +1,28 @@
1
+ # This file should be copied into a test ending in 'tests.rb' so that
2
+ # the Rakefile knows it's a test.
3
+
4
+ require "set-standalone-test-paths.rb" unless $started_from_rakefile
5
+ require 'test/unit'
6
+ require 's4t-utils'
7
+ include S4tUtils
8
+
9
+ ## Require either the particular file under test like this:
10
+ # require '!REPLACE_ME_FILE!/my-file'
11
+ ## or the entire package:
12
+ # require '!REPLACE_ME_FILE!'
13
+
14
+ class TestName < Test::Unit::TestCase
15
+ ## You probably want to include your library so that you don't have
16
+ ## to tack !REPLACE_ME_MODULE!:: onto every name, but I won't assume
17
+ ## that.
18
+ # include !REPLACE_ME_MODULE!
19
+
20
+ def setup
21
+ end
22
+
23
+ def teardown
24
+ end
25
+
26
+ def test_something
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module !REPLACE_ME_MODULE!
2
+ Version = '0.1.0'
3
+ end
@@ -0,0 +1,23 @@
1
+ require 's4t-utils/capturing-globals'
2
+ require 's4t-utils/error-handling'
3
+ require 's4t-utils/more-assertions'
4
+ require 's4t-utils/claims'
5
+ require 's4t-utils/friendly-format'
6
+ require 's4t-utils/rake-task-helpers'
7
+ require 's4t-utils/svn-file-movement'
8
+ require 's4t-utils/hacks'
9
+ require 's4t-utils/command-line'
10
+ require 's4t-utils/test-util'
11
+ require 's4t-utils/os'
12
+
13
+ require 'pp'
14
+
15
+ # Tolerate typos
16
+ S4TUtils=S4tUtils
17
+ S4tUtil=S4tUtils
18
+ S4TUtil=S4tUtils
19
+
20
+ # Note, unless otherwise noted, all methods defined in S4tUtils
21
+ # are both module functions and instance functions.
22
+ module S4tUtils
23
+ end
@@ -0,0 +1,93 @@
1
+ require 'stringio'
2
+
3
+ module S4tUtils
4
+
5
+ module_function
6
+
7
+ # Run the block, capturing output to $stderr in a string.
8
+ # That string is the method's return value.
9
+ def capturing_stderr
10
+ old_stderr = $stderr
11
+ new_stderr = StringIO.new
12
+ begin
13
+ $stderr = new_stderr
14
+ yield
15
+ ensure
16
+ $stderr = old_stderr
17
+ end
18
+ new_stderr.string
19
+ end
20
+
21
+ # Run the block, replacing the values of environment variables
22
+ # with the values given in the hash _settings_. The environment
23
+ # variables are restored when the method returns.
24
+ def with_environment_vars(settings)
25
+ begin
26
+ old = {}
27
+ settings.each { | key, value |
28
+ old[key] = ENV[key]
29
+ ENV[key] = value
30
+ }
31
+ yield
32
+ ensure
33
+ settings.each_key { | key |
34
+ ENV[key] = old[key]
35
+ }
36
+ end
37
+ end
38
+
39
+ # Run the block with the _HOME_ environment variable set to the
40
+ # current working directory.
41
+ def with_home_right_here
42
+ begin
43
+ old_home = ENV['HOME']
44
+ ENV['HOME'] = '.'
45
+ yield
46
+ ensure
47
+ ENV['HOME'] = @old_home
48
+ end
49
+ end
50
+
51
+ # Run the block with the given _file_ (named by a string) deleted before
52
+ # and after.
53
+ def erasing_local_config_file(file)
54
+ with_home_right_here {
55
+ begin
56
+ File.delete(file) if File.exist?(file)
57
+ yield
58
+ ensure
59
+ File.delete(file) if File.exist?(file)
60
+ end
61
+ }
62
+ end
63
+
64
+ # Run the block. During the execution, the contents of _file_ (named by
65
+ # a string) is replaced with _contents_.
66
+ def with_local_config_file(file, contents)
67
+ erasing_local_config_file(file) do
68
+ File.open(file, 'w') do | io |
69
+ io.puts(contents.to_s)
70
+ end
71
+ yield
72
+ end
73
+ end
74
+
75
+ # Run the block. During execution, _ARGV_'s is set as if the
76
+ # script had been executed with _string_ as its argument list.
77
+ # If the block tries to exit, with_command_args will instead throw
78
+ # a StandardError.
79
+ def with_command_args(string)
80
+ begin
81
+ old_argv = ARGV.dup
82
+ ARGV.replace(string.split)
83
+ yield
84
+ rescue SystemExit => ex
85
+ replacement = StandardError.new(ex.message)
86
+ replacement.set_backtrace(ex.backtrace)
87
+ raise replacement
88
+ ensure
89
+ ARGV.replace(old_argv)
90
+ end
91
+ end
92
+
93
+ end
@@ -0,0 +1,20 @@
1
+ module S4tUtils
2
+
3
+ module_function
4
+
5
+ # A StandardError is thrown if the _fact_ the user claims is true
6
+ # is actually false. The _block_ is called to provide the exception
7
+ # message.
8
+ def user_claims(fact, &block)
9
+ raise StandardError.new(block.call) unless fact
10
+ end
11
+
12
+ # A StandardError is thrown if the _fact_ the user disputes is
13
+ # nevertheless true. The _block_ is called to provide the exception
14
+ # message.
15
+ def user_disputes(fact, &block)
16
+ user_claims(!fact, &block)
17
+ end
18
+ end
19
+
20
+
@@ -0,0 +1,18 @@
1
+ module S4tUtils
2
+
3
+ module_function
4
+
5
+ # Ask the question contained in the _question_lines_, prompt, and
6
+ # wait for an answer. If the stripped value read from STDIN is
7
+ # empty, use the _default_answer_.
8
+ def ask(default_answer, *question_lines)
9
+ puts question_lines
10
+ print "[#{default_answer}] => "
11
+ answer = STDIN.readline.strip
12
+ answer = default_answer.to_s if answer == ''
13
+ answer
14
+ end
15
+
16
+ end
17
+
18
+
@@ -0,0 +1,26 @@
1
+ module S4tUtils
2
+
3
+ module_function
4
+
5
+ # Typically used to wrap the execution of an entire script.
6
+ # If an exception is thrown, a terse message is printed (to $stderr)
7
+ # instead of a stack dump. The message printed is gotten from the
8
+ # exception.
9
+ def with_pleasant_exceptions
10
+ yield
11
+ rescue SystemExit
12
+ raise
13
+ rescue Exception => ex
14
+ $stderr.puts(ex.message)
15
+ end
16
+
17
+ # with_pleasant_exceptions swallows the stack trace, which you
18
+ # want to see during debugging. The easy way to see it is to add
19
+ # 'out' to that message, producing this one. To reduce the chance
20
+ # you'll forget to make exceptions pleasant again, a note that
21
+ # exceptions are turned off is always printed to $stderr.
22
+ def without_pleasant_exceptions
23
+ $stderr.puts "Note: exception handling turned off."
24
+ yield
25
+ end
26
+ end
@@ -0,0 +1,35 @@
1
+ #--
2
+ # Note: see also <http://englishext.rubyforge.org/>
3
+ #++
4
+
5
+ module S4tUtils
6
+
7
+ module_function
8
+
9
+ # Use _connector_ to join _array_ into a human-friendly list.
10
+ #
11
+ #
12
+ # friendly_list("or", [1]) => "'1'"
13
+ # friendly_list("or"), [1, 2] => "'1' or '2'"
14
+ # friendly_list("or"), [1, 2, 3] => "'1', '2', or '3'"
15
+ def friendly_list(connector, array)
16
+ quoted = array.collect { | elt | "'" + elt.to_s + "'" }
17
+ case array.length
18
+ when 0
19
+ ""
20
+ when 1
21
+ quoted[0]
22
+ when 2
23
+ quoted[0] + " #{connector} " + quoted[1]
24
+ else
25
+ quoted[0...-1].join(", ") + ", #{connector} #{quoted.last}"
26
+ end
27
+ end
28
+
29
+ # Produces a version of a string that can be typed after a :
30
+ # (Can also be safely given at a command-line prompt.)
31
+ def symbol_safe_name(name)
32
+ name.to_s.gsub(/\W/, '')
33
+ end
34
+ end
35
+
@@ -0,0 +1,55 @@
1
+ module S4tUtils
2
+
3
+ module_function
4
+
5
+ # The return value of prog1 is the _retval_. Before that's returned,
6
+ # though, the _retval_ is yielded to the block. This method is an
7
+ # alternative to stashing a value in a temporary, fiddling around, then
8
+ # returning the temporary. Here's an example:
9
+ #
10
+ # prog1(1+1) { | s | puts "Sum is #{s}."} # => 2
11
+ #
12
+ # The name "prog1" is ancient Lisp jargon.
13
+ def prog1(retval)
14
+ yield(retval)
15
+ retval
16
+ end
17
+
18
+ # A way of putting debugging statements in code that requires less
19
+ # typing than +puts+.
20
+ #
21
+ # pi [1, 2, 3], 'input' # => 'input: [1, 2, 3]
22
+ #
23
+ # The _arg_ is printed using +inspect+. If _leader_ isn't given,
24
+ # nothing is printed before _arg_.
25
+ #
26
+ # pi returns its _arg_, which is occasionally useful for sticking
27
+ # debugging into the middle of complicated expressions.
28
+ def pi(arg, leader=nil)
29
+ leader = (leader == nil) ? '' : leader + ': '
30
+ prog1(arg) { puts leader + arg.inspect }
31
+ end
32
+
33
+
34
+
35
+ # An ArgForwarder is associated with a _target_. It forwards messages
36
+ # sent to it to the target, passing along any arguments to the method.
37
+ # So far, so boring. But an ArgForwarder is also created with some
38
+ # _added_args_. When the ArgForwarder forwards, it prepends those
39
+ # _added_args_ to the message's given arguments.
40
+ #
41
+ # array = []
42
+ # forwarder = ArgForwarder.new(array, 5)
43
+ # forwarder.push
44
+ # assert_equal([5], array)
45
+ class ArgForwarder
46
+ def initialize(target, *added_args)
47
+ @target = target
48
+ @added_args = added_args
49
+ end
50
+
51
+ def method_missing(method, *args) # :nodoc:
52
+ @target.send(method, *(@added_args + args))
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,120 @@
1
+ # This is loaded by an executable script in one of two cases:
2
+ #
3
+ # It's a development version living in the bin part of this directory
4
+ # structure (but it can invoked from any place).
5
+ #
6
+ # project/
7
+ # bin/
8
+ # lib/
9
+ # project/
10
+ # third-party/
11
+ # s4t-utils/
12
+ # this file
13
+ #
14
+ # It's a deployed version living in some random place, with
15
+ # the site_ruby directory in the page.
16
+ #
17
+ # site_ruby/1.8/
18
+ # project/
19
+ # third-party/
20
+ # s4t-utils/
21
+ # this file
22
+ #
23
+ #
24
+ # In order for this file to have been required in both cases, the following
25
+ # code is executed in the caller:
26
+ #
27
+ #
28
+ # $:.unshift((Pathname.new(__FILE__).parent.parent + 'lib').to_s)
29
+ # require 'package/third-party/s4t-utils/load-path-auto-adjuster'
30
+ #
31
+ # In the first case, that will put something like "../lib" on the load
32
+ # path. In the second case, it will put harmless garbage on the path
33
+ # (harmless because it won't contain this file, which will still be
34
+ # found somewhere later in the load path).
35
+ #
36
+ # The first thing this file does is pop that off, it having done its job.
37
+ # In the first (development) case, it puts the following on the load path:
38
+ # project/lib & project/lib/project/third-party & project
39
+ # ('project' is added so that <require 'test/util-file'> works.)
40
+ #
41
+ # In the second, it adds only the third-party library and takes care
42
+ # to add it just after whatever component in the path contains this
43
+ # file. (It will thus not interfere with clashing packages earlier
44
+ # in the path.)
45
+ # site_ruby/1.8/project/third-party
46
+ # since site_ruby/1.8 (or the equivalent) is already on there.
47
+
48
+ require 'rubygems'
49
+ require 'pathname'
50
+
51
+ module S4tUtils
52
+ module Hidden # :nodoc: all
53
+
54
+ class Arranger
55
+ def initialize(third_party)
56
+ @third_party_lib = third_party
57
+ @project_lib = third_party.parent.parent
58
+ @test_util_root = @project_lib.parent
59
+ end
60
+
61
+ def self.arrange_path_around(third_party)
62
+ new(third_party).arrange
63
+ end
64
+
65
+ def arrange
66
+ add_third_party_gems
67
+ if project_lib_already_in_path?
68
+ just_add_third_party_after_project_lib
69
+ else
70
+ add_everything_at_front
71
+ end
72
+ end
73
+
74
+
75
+ def add_third_party_gems
76
+ # When RubyGems 0.8.11 gets clear_paths, it does not clear the
77
+ # cache used by Gem's overriding version of require(), so if
78
+ # this is loaded after the first Gem is required, it will have
79
+ # no effect on later uses of require(). (But it does affect
80
+ # require_gem.)
81
+ #
82
+ ENV['GEM_PATH']=(@third_party_lib+'gems').to_s
83
+ Gem.clear_paths
84
+ end
85
+
86
+ def project_lib_already_in_path?
87
+ $:.include?(@project_lib.to_s)
88
+ end
89
+
90
+ def just_add_third_party_after_project_lib
91
+ $:.each_with_index do | path_element, index |
92
+ if path_element == @project_lib.to_s
93
+ $:[index+1,0] = @third_party_lib.to_s
94
+ return
95
+ end
96
+ end
97
+ fail "No place to put third_party library."
98
+ end
99
+
100
+ def add_everything_at_front
101
+ $:.unshift(@test_util_root.to_s)
102
+ $:.unshift(@third_party_lib.to_s)
103
+ $:.unshift(@project_lib.to_s) # This is now first
104
+ end
105
+ end
106
+
107
+ def self.auto_adjust_load_path
108
+ $:.shift # Remove extra element used to find this file.
109
+
110
+ # Having loaded us, __FILE__ is something like this:
111
+ # ...lib.../package/third-party/s4t-utils/load-path-auto-adjuster.rb
112
+ relative_third_party = Pathname.new(__FILE__).parent.parent
113
+ # Pathname#real_path doesn't work on Windows (1.8.2). Grr.
114
+ third_party = Pathname.new(File.expand_path(relative_third_party.to_s))
115
+ Arranger.arrange_path_around(third_party)
116
+ end
117
+
118
+ auto_adjust_load_path
119
+ end
120
+ end
@@ -0,0 +1,35 @@
1
+ module Test
2
+ module Unit
3
+
4
+ # Some additional Test::Unit assertions.
5
+ module Assertions
6
+ # Same as +assert+. I just like it better.
7
+ def assert_true(boolean, message = nil)
8
+ assert(boolean, message)
9
+ end
10
+
11
+ # Assert that the _boolean_ is false.
12
+ def assert_false(boolean, message = nil)
13
+ _wrap_assertion do
14
+ assert_block(build_message(message, "<?> should be false or nil.", boolean)) { !boolean }
15
+ end
16
+ end
17
+
18
+ # Like +assert_raise+, but the raised exception must contain a
19
+ # +message+ matching (as in +assert_match+) the _message_ argument.
20
+ def assert_raise_with_matching_message(exception_class, message, &block)
21
+ exception = assert_raise(exception_class, &block)
22
+ assert_match(message, exception.message)
23
+ end
24
+ alias_method :assert_raises_with_matching_message,
25
+ :assert_raise_with_matching_message
26
+
27
+ # Assert that the block tried to +exit+.
28
+ def assert_wants_to_exit
29
+ assert_raise(SystemExit) do
30
+ yield
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end