grizzled-ruby 0.1.1 → 0.1.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/bin/grinc +151 -0
- data/lib/grizzled/dir.rb +10 -0
- data/lib/grizzled/fileutil.rb +3 -3
- data/lib/grizzled/fileutil/includer.rb +10 -8
- data/lib/grizzled/fileutil/ziputil.rb +52 -49
- data/lib/grizzled/forwarder.rb +7 -0
- data/lib/grizzled/stack.rb +6 -2
- data/lib/grizzled/string/template.rb +19 -19
- data/lib/grizzled/unix.rb +4 -2
- data/test/fileutil/tc_includer.rb +114 -0
- data/test/fileutil/tc_make_dir_tree.rb +55 -0
- data/test/fileutil/tc_zip.rb +139 -0
- data/test/string/tc_template.rb +68 -0
- data/test/tc_forwarder.rb +89 -0
- data/test/tc_stack.rb +83 -0
- metadata +23 -11
data/bin/grinc
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# See the man page or http://software.clapper.org/grizzled-ruby/grinc/
|
4
|
+
# for documentation.
|
5
|
+
#--
|
6
|
+
# This software is released under a BSD license, adapted from
|
7
|
+
# http://opensource.org/licenses/bsd-license.php
|
8
|
+
#
|
9
|
+
# Copyright (c) 2011, Brian M. Clapper
|
10
|
+
# All rights reserved.
|
11
|
+
#
|
12
|
+
# Redistribution and use in source and binary forms, with or without
|
13
|
+
# modification, are permitted provided that the following conditions are
|
14
|
+
# met:
|
15
|
+
#
|
16
|
+
# * Redistributions of source code must retain the above copyright notice,
|
17
|
+
# this list of conditions and the following disclaimer.
|
18
|
+
#
|
19
|
+
# * Redistributions in binary form must reproduce the above copyright
|
20
|
+
# notice, this list of conditions and the following disclaimer in the
|
21
|
+
# documentation and/or other materials provided with the distribution.
|
22
|
+
#
|
23
|
+
# * Neither the names "clapper.org", "Grizzled Ruby Library", nor the
|
24
|
+
# names of its contributors may be used to endorse or promote products
|
25
|
+
# derived from this software without specific prior written permission.
|
26
|
+
#
|
27
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
28
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
29
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
30
|
+
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
31
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
32
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
33
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
34
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
35
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
36
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
37
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
38
|
+
#++
|
39
|
+
|
40
|
+
require 'optparse'
|
41
|
+
require 'grizzled/fileutil/includer'
|
42
|
+
|
43
|
+
include Grizzled::FileUtil
|
44
|
+
|
45
|
+
# ---------------------------------------------------------------------------
|
46
|
+
# Constants
|
47
|
+
# ---------------------------------------------------------------------------
|
48
|
+
|
49
|
+
DEFAULT_MAX_NEST = 100
|
50
|
+
PROGRAM_NAME = 'grinc'
|
51
|
+
|
52
|
+
# ---------------------------------------------------------------------------
|
53
|
+
# Classes
|
54
|
+
# ---------------------------------------------------------------------------
|
55
|
+
|
56
|
+
class Parameters
|
57
|
+
attr_reader :output, :max_nesting, :input_paths
|
58
|
+
|
59
|
+
def initialize(options_hash, argv)
|
60
|
+
@output = options_hash[:output]
|
61
|
+
@max_nesting = options_hash[:max_nesting] || DEFAULT_MAX_NEST
|
62
|
+
@input_paths = argv.length == 0 ? nil : argv
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_s
|
66
|
+
inspect
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class UsageError < StandardError; end
|
71
|
+
|
72
|
+
# ---------------------------------------------------------------------------
|
73
|
+
# Parameter parsing
|
74
|
+
# ---------------------------------------------------------------------------
|
75
|
+
|
76
|
+
def parse_params
|
77
|
+
options_hash = {}
|
78
|
+
error = nil
|
79
|
+
option_parser = OptionParser.new do |opts|
|
80
|
+
opts.program_name = PROGRAM_NAME
|
81
|
+
opts.banner = "Usage: #{opts.program_name} [OPTIONS] inputfile ..."
|
82
|
+
opts.separator ''
|
83
|
+
opts.separator 'OPTIONS:'
|
84
|
+
|
85
|
+
opts.on('-o FILE', 'Output file. Default: standard output.') do |f|
|
86
|
+
options_hash[:output] = f
|
87
|
+
end
|
88
|
+
|
89
|
+
opts.on('-n', '--nesting n',
|
90
|
+
"Max nesting. Default: #{DEFAULT_MAX_NEST}") do |n|
|
91
|
+
if n !~ /^[0-9]+$/
|
92
|
+
error = "Non-numeric parameter \"#{n}\" to -n option."
|
93
|
+
end
|
94
|
+
options_hash[:max_nesting] = n.to_i
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
begin
|
99
|
+
option_parser.parse!(ARGV)
|
100
|
+
rescue OptionParser::InvalidOption => ex
|
101
|
+
error = ex.to_s
|
102
|
+
end
|
103
|
+
|
104
|
+
if error
|
105
|
+
$stderr.puts(error) unless error.nil?
|
106
|
+
option_parser.display
|
107
|
+
raise UsageError.new
|
108
|
+
end
|
109
|
+
|
110
|
+
if ARGV.length == 0
|
111
|
+
options_hash[:input_files] = nil
|
112
|
+
else
|
113
|
+
options_hash[:input_files] = ARGV
|
114
|
+
end
|
115
|
+
|
116
|
+
Parameters.new(options_hash, ARGV)
|
117
|
+
end
|
118
|
+
|
119
|
+
def process_include(input_file, output_file, max_nesting = 100)
|
120
|
+
Includer.new(input_file, :max_nesting => max_nesting).each do |line|
|
121
|
+
output_file.write(line)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# ---------------------------------------------------------------------------
|
126
|
+
# Main logic
|
127
|
+
# ---------------------------------------------------------------------------
|
128
|
+
|
129
|
+
begin
|
130
|
+
params = parse_params
|
131
|
+
out = params.output.nil? ? $stderr : File.open(params.output, 'w')
|
132
|
+
|
133
|
+
if params.input_paths.nil?
|
134
|
+
process_include($stdin, out, params.max_nesting)
|
135
|
+
else
|
136
|
+
params.input_paths.each do |f|
|
137
|
+
process_include(File.open(f), out, params.max_nesting)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
rescue UsageError
|
142
|
+
exit 1
|
143
|
+
|
144
|
+
rescue
|
145
|
+
$stderr.puts("#{PROGRAM_NAME}: #{$!}")
|
146
|
+
exit 1
|
147
|
+
|
148
|
+
else
|
149
|
+
exit 0
|
150
|
+
end
|
151
|
+
|
data/lib/grizzled/dir.rb
CHANGED
@@ -43,6 +43,11 @@ class Dir
|
|
43
43
|
# walked top-down, not depth-first. To terminate the traversal, the block
|
44
44
|
# should return +false+. Anything else (including +nil+) continues the
|
45
45
|
# traversal.
|
46
|
+
#
|
47
|
+
# Parameters:
|
48
|
+
#
|
49
|
+
# dirname:: The name (path) of the directory to walk.
|
50
|
+
# block:: The block to invoke on each entry.
|
46
51
|
def self.walk(dirname, &block)
|
47
52
|
Grizzled::Directory.walk(dirname, &block)
|
48
53
|
end
|
@@ -64,6 +69,11 @@ module Grizzled
|
|
64
69
|
# directory is walked top-down, not depth-first. To terminate the
|
65
70
|
# traversal, the block should return +false+. Anything else (including
|
66
71
|
# +nil+) continues the traversal.
|
72
|
+
#
|
73
|
+
# Parameters:
|
74
|
+
#
|
75
|
+
# dirname:: The name (path) of the directory to walk.
|
76
|
+
# block:: The block to invoke on each entry.
|
67
77
|
def self.walk(dirname, &block)
|
68
78
|
if block.call(Dir.new(dirname)) != false
|
69
79
|
Dir.entries(dirname).each do |entry|
|
data/lib/grizzled/fileutil.rb
CHANGED
@@ -88,9 +88,9 @@ module Grizzled
|
|
88
88
|
#
|
89
89
|
# Parameters:
|
90
90
|
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
91
|
+
# directory:: The starting directory, which is created if it does not
|
92
|
+
# exist.
|
93
|
+
# tree:: The entry tree, as described above
|
94
94
|
#
|
95
95
|
# Returns:
|
96
96
|
#
|
@@ -123,17 +123,19 @@ module Grizzled
|
|
123
123
|
#
|
124
124
|
# Parameters:
|
125
125
|
#
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
126
|
+
# source:: A string, representing a file name or URL (http, https or
|
127
|
+
# ftp), a +File+ object, or an object with an +each_line+
|
128
|
+
# method that returns individual lines of input.
|
129
|
+
# options:: Various processing options. See below.
|
130
130
|
#
|
131
131
|
# Options:
|
132
132
|
#
|
133
|
-
#
|
134
|
-
#
|
135
|
-
#
|
136
|
-
#
|
133
|
+
# **NOTE**: Options are symbols (e.g., +:recursive+).
|
134
|
+
#
|
135
|
+
# max_nesting:: Maximum include nesting level. Default: 100
|
136
|
+
# include_pattern:: String regex pattern to match include directives.
|
137
|
+
# Must have a single regex group for the file name
|
138
|
+
# or URL. Default: ^%include\s"([^"]+)"
|
137
139
|
def initialize(source, options={})
|
138
140
|
@max_nesting = options.fetch(:max_nesting, 100)
|
139
141
|
inc_pattern = options.fetch(:include_pattern, '^%include\s"([^"]+)"')
|
@@ -58,10 +58,10 @@ module Grizzled
|
|
58
58
|
# class mixes in methods that will allow you to zip up files. Related
|
59
59
|
# modules and classes:
|
60
60
|
#
|
61
|
-
#
|
61
|
+
# Grizzled::FileUtil::Zipper:: A class that includes this module
|
62
62
|
# and can be instantiated by itself.
|
63
|
-
#
|
64
|
-
#
|
63
|
+
# Grizzled::FileUtil::UnzipMixin:: A module mixin for unzipping zip files.
|
64
|
+
# Grizzled::FileUtil::Unzipper:: A class that includes `UnzipMixin'
|
65
65
|
# and can be instantiated by itself.
|
66
66
|
module ZipMixin
|
67
67
|
|
@@ -69,31 +69,33 @@ module Grizzled
|
|
69
69
|
#
|
70
70
|
# Parameters:
|
71
71
|
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
72
|
+
# zip_file:: The zip file to open. The file is created if it doesn't
|
73
|
+
# already exists.
|
74
|
+
# directory:: The directory whose contents are to be included in
|
75
|
+
# the file.
|
76
|
+
# options:: Options hash, as described below.
|
77
|
+
# select:: If a block (+select+) is given, then +zip+ passes each
|
78
|
+
# file or directory to the block and only adds the entry
|
79
|
+
# to the zip file if the block returns +true+. If no
|
80
|
+
# block is given, then all files and directories are
|
81
|
+
# added (subject also to the +:recursive+ option, below).
|
82
82
|
#
|
83
83
|
# Options:
|
84
84
|
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
85
|
+
# **NOTE**: Options are symbols (e.g., +:recursive+).
|
86
|
+
#
|
87
|
+
# recursive:: If +false+, only zip the files in the directory; if
|
88
|
+
# +true+ (the default), recursively zip the entire
|
89
|
+
# directory.
|
90
|
+
# dir_at_top:: If +false+, don't include zip the directory itself
|
91
|
+
# (i.e., the top-level files will be at the top level
|
92
|
+
# of the zip file). If +true+ (the default), the
|
93
|
+
# the directory itself (the basename) will be the
|
94
|
+
# top-level element of the zip file.
|
95
|
+
# recreate:: If +true+, remove the zip file if it exists already,
|
96
|
+
# so it's recreated from scratch. If +false+ (the
|
97
|
+
# default), don't recreate the zip file if it doesn't
|
98
|
+
# exist; instead, update the existing file.
|
97
99
|
#
|
98
100
|
# Returns:
|
99
101
|
#
|
@@ -157,35 +159,37 @@ module Grizzled
|
|
157
159
|
# class mixes in methods that will allow you to unzip zip files.
|
158
160
|
# Related modules and classes:
|
159
161
|
#
|
160
|
-
#
|
162
|
+
# Grizzled::FileUtil::Zipper:: A class that includes this module
|
161
163
|
# and can be instantiated by itself.
|
162
|
-
#
|
163
|
-
#
|
164
|
+
# Grizzled::FileUtil::ZipMixin:: A module mixin for zipping zip files.
|
165
|
+
# Grizzled::FileUtil::Unzipper:: A class that includes `UnzipMixin'
|
164
166
|
# and can be instantiated by itself.
|
165
167
|
module UnzipMixin
|
166
168
|
# Unzips a zip file into a directory.
|
167
169
|
#
|
168
170
|
# Parameters:
|
169
171
|
#
|
170
|
-
#
|
171
|
-
#
|
172
|
-
#
|
173
|
-
#
|
174
|
-
#
|
175
|
-
#
|
176
|
-
#
|
177
|
-
#
|
178
|
-
#
|
172
|
+
# zip_file:: The zip file to unzip.
|
173
|
+
# directory:: The directory into which to unzip the file. The
|
174
|
+
# directory is created if it doesn't already exist.
|
175
|
+
# options:: Options hash, as described below.
|
176
|
+
# select:: If a block (+select+) is given, then +unzip+ passes each
|
177
|
+
# zip file entry name to the block and only unzips the
|
178
|
+
# entry if the block returns +true+. If no block is
|
179
|
+
# given, then everything is unzipped (subject also to
|
180
|
+
# the +:recursive+ option, below).
|
179
181
|
#
|
180
182
|
# Options:
|
181
183
|
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
185
|
-
#
|
186
|
-
#
|
187
|
-
#
|
188
|
-
#
|
184
|
+
# **NOTE**: Options are symbols (e.g., +:recursive+).
|
185
|
+
#
|
186
|
+
# recursive:: If +false+, only extract the top-level files from the
|
187
|
+
# zip file. If +true+ (the default), recursively
|
188
|
+
# extract everything.
|
189
|
+
# overwrite:: If +false+ (the default), do not overwrite existing
|
190
|
+
# files in the directory. If +true+, overwrite
|
191
|
+
# any existing files in the directory with extracted
|
192
|
+
# zip files whose names match.
|
189
193
|
#
|
190
194
|
# Example:
|
191
195
|
#
|
@@ -198,7 +202,6 @@ module Grizzled
|
|
198
202
|
# unzip zipfile_path, d
|
199
203
|
# # muck with unpacked contents
|
200
204
|
# end
|
201
|
-
|
202
205
|
def unzip(zip_file, directory, options = {}, &select)
|
203
206
|
overwrite = options.fetch(:overwrite, false)
|
204
207
|
recurse = options.fetch(:recursive, true)
|
@@ -228,10 +231,10 @@ module Grizzled
|
|
228
231
|
#
|
229
232
|
# Parameters:
|
230
233
|
#
|
231
|
-
#
|
232
|
-
#
|
233
|
-
#
|
234
|
-
#
|
234
|
+
# zip_file:: The zip file to unzip.
|
235
|
+
# block:: Block to execute on each entry. If omitted, an
|
236
|
+
# Enumerator is returned. The block receives a string
|
237
|
+
# representing the path of the item in the file.
|
235
238
|
def zip_file_entries(zip_file, &block)
|
236
239
|
if not block_given?
|
237
240
|
a = []
|
data/lib/grizzled/forwarder.rb
CHANGED
@@ -70,6 +70,13 @@ module Grizzled
|
|
70
70
|
|
71
71
|
# Forward all unimplemented method calls to +obj+, except those
|
72
72
|
# whose symbols are listed in the +exceptions+ array.
|
73
|
+
#
|
74
|
+
# Parameters:
|
75
|
+
#
|
76
|
+
# obj:: The object to which to forward unimplemented method calls
|
77
|
+
# exception+:: A list of symbols for unimplemented methods that should
|
78
|
+
# not be forwarded to +obj+. Note: You do _not_ have to put
|
79
|
+
# methods you've implemented in here.
|
73
80
|
def forward_to(obj, exceptions=[])
|
74
81
|
@forward_obj = obj
|
75
82
|
|
data/lib/grizzled/stack.rb
CHANGED
@@ -53,8 +53,8 @@ module Grizzled
|
|
53
53
|
#
|
54
54
|
# Parameters:
|
55
55
|
#
|
56
|
-
#
|
57
|
-
#
|
56
|
+
# pop_empty_nil:: +true+ if popping an empty stack should just return
|
57
|
+
# +nil+, +false+ if it should thrown an exception.
|
58
58
|
def initialize(pop_empty_nil=true)
|
59
59
|
@the_stack = []
|
60
60
|
@pop_empty_nil = pop_empty_nil
|
@@ -93,6 +93,10 @@ module Grizzled
|
|
93
93
|
#
|
94
94
|
# stack = Stack.new
|
95
95
|
# [1, 2, 3].each {|i| stack.push i}
|
96
|
+
#
|
97
|
+
# Parameters:
|
98
|
+
#
|
99
|
+
# element:: The object to push onto the stack.
|
96
100
|
def push(element)
|
97
101
|
if element.class == Array
|
98
102
|
element.each {|e| @the_stack.push e}
|
@@ -81,14 +81,14 @@ module Grizzled
|
|
81
81
|
#
|
82
82
|
# Parameters:
|
83
83
|
#
|
84
|
-
#
|
84
|
+
# +resolver+:: A hash-like object that can take a variable name (via
|
85
85
|
# the +[]+ function) and resolve its value, returning
|
86
86
|
# the value (which is converted to string) or +nil+.
|
87
|
-
#
|
87
|
+
# +options+:: hash of options. See below.
|
88
88
|
#
|
89
89
|
# Options:
|
90
90
|
#
|
91
|
-
#
|
91
|
+
# +:safe+:: +true+ for a safe template that substitutes a blank
|
92
92
|
# string for a non-existent variable, instead of
|
93
93
|
# throwing an exception. Defaults to +true+.
|
94
94
|
def initialize(resolver, options={})
|
@@ -108,7 +108,7 @@ module Grizzled
|
|
108
108
|
#
|
109
109
|
# Parameters:
|
110
110
|
#
|
111
|
-
#
|
111
|
+
# +s+:: the string in which to replace variable references
|
112
112
|
#
|
113
113
|
# Returns the substituted result.
|
114
114
|
def substitute(s)
|
@@ -135,7 +135,7 @@ module Grizzled
|
|
135
135
|
#
|
136
136
|
# Parameters:
|
137
137
|
#
|
138
|
-
#
|
138
|
+
# +s+:: the string
|
139
139
|
#
|
140
140
|
# Returns a +Variable+ object, or +nil+.
|
141
141
|
def find_variable_ref(s)
|
@@ -147,8 +147,8 @@ module Grizzled
|
|
147
147
|
#
|
148
148
|
# Parameters:
|
149
149
|
#
|
150
|
-
#
|
151
|
-
#
|
150
|
+
# +name+:: Variable name
|
151
|
+
# +default+:: Default value, or +nil+
|
152
152
|
def get_variable(name, default)
|
153
153
|
|
154
154
|
def handle_no_value(default, name)
|
@@ -193,17 +193,17 @@ module Grizzled
|
|
193
193
|
#
|
194
194
|
# Parameters:
|
195
195
|
#
|
196
|
-
#
|
196
|
+
# +resolver+:: A hash-like object that can take a variable name (via
|
197
197
|
# the +[]+ function) and resolve its value, returning
|
198
198
|
# the value (which is converted to string) or +nil+.
|
199
|
-
#
|
199
|
+
# +options+:: hash of options. See below.
|
200
200
|
#
|
201
201
|
# Options:
|
202
202
|
#
|
203
|
-
#
|
203
|
+
# +:safe+:: +true+ for a safe template that substitutes a blank
|
204
204
|
# string for a non-existent variable, instead of
|
205
205
|
# throwing an exception. Defaults to +true+.
|
206
|
-
#
|
206
|
+
# +:var_pattern+:: Regular expression pattern (as a string, not a
|
207
207
|
# Regexp object) to match a variable name. Defaults
|
208
208
|
# to "[A-Za-z0-9_]+"
|
209
209
|
def initialize(resolver, options={})
|
@@ -225,7 +225,7 @@ module Grizzled
|
|
225
225
|
#
|
226
226
|
# Parameters:
|
227
227
|
#
|
228
|
-
#
|
228
|
+
# +s+:: the string in which to replace variable references
|
229
229
|
#
|
230
230
|
# Returns the substituted result.
|
231
231
|
def substitute(s)
|
@@ -269,7 +269,7 @@ module Grizzled
|
|
269
269
|
#
|
270
270
|
# Parameters:
|
271
271
|
#
|
272
|
-
#
|
272
|
+
# +s+:: the string
|
273
273
|
#
|
274
274
|
# Returns a +Variable+ object, or +nil+.
|
275
275
|
def find_variable_ref(s)
|
@@ -319,17 +319,17 @@ module Grizzled
|
|
319
319
|
#
|
320
320
|
# Parameters:
|
321
321
|
#
|
322
|
-
#
|
322
|
+
# +resolver+:: A hash-like object that can take a variable name (via
|
323
323
|
# the +[]+ function) and resolve its value, returning
|
324
324
|
# the value (which is converted to string) or +nil+.
|
325
|
-
#
|
325
|
+
# +options+:: hash of options. See below.
|
326
326
|
#
|
327
327
|
# Options:
|
328
328
|
#
|
329
|
-
#
|
329
|
+
# +:safe+:: +true+ for a safe template that substitutes a blank
|
330
330
|
# string for a non-existent variable, instead of
|
331
331
|
# throwing an exception. Defaults to +true+.
|
332
|
-
#
|
332
|
+
# +:var_pattern+:: Regular expression pattern (as a string, not a
|
333
333
|
# Regexp object) to match a variable name. Defaults
|
334
334
|
# to "[A-Za-z0-9_]+"
|
335
335
|
def initialize(resolver, options={})
|
@@ -350,7 +350,7 @@ module Grizzled
|
|
350
350
|
#
|
351
351
|
# Parameters:
|
352
352
|
#
|
353
|
-
#
|
353
|
+
# +s+:: the string in which to replace variable references
|
354
354
|
#
|
355
355
|
# Returns the substituted result.
|
356
356
|
def substitute(s)
|
@@ -392,7 +392,7 @@ module Grizzled
|
|
392
392
|
#
|
393
393
|
# Parameters:
|
394
394
|
#
|
395
|
-
#
|
395
|
+
# +s+:: the string
|
396
396
|
#
|
397
397
|
# Returns a +Variable+ object, or +nil+.
|
398
398
|
def find_variable_ref(s)
|
data/lib/grizzled/unix.rb
CHANGED
@@ -55,8 +55,10 @@ module Grizzled
|
|
55
55
|
|
56
56
|
# Run a block of code as this user.
|
57
57
|
#
|
58
|
-
#
|
59
|
-
#
|
58
|
+
# Parameters:
|
59
|
+
#
|
60
|
+
# block:: the block to execute as that user. It will receive this
|
61
|
+
# +User+ object as a parameter.
|
60
62
|
#
|
61
63
|
# This function will only run as 'root'.
|
62
64
|
#
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require '../test_helper'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'grizzled/fileutil/includer'
|
5
|
+
|
6
|
+
include Grizzled::FileUtil
|
7
|
+
|
8
|
+
class IncluderTestDriver < Test::Unit::TestCase
|
9
|
+
include GrizzledTestHelper
|
10
|
+
|
11
|
+
def test_successful_file_include
|
12
|
+
make_include_file do |test_file|
|
13
|
+
inc = Includer.new(test_file.main_file)
|
14
|
+
lines = inc.readlines.map {|line| line.chomp}
|
15
|
+
assert_equal(['one-1', 'one-2', 'two-2', 'two-1'], lines)
|
16
|
+
inc.close
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_recursive_include
|
21
|
+
temp = Tempfile.new('inctest')
|
22
|
+
temp.write <<EOF
|
23
|
+
%include "#{temp.path}"
|
24
|
+
EOF
|
25
|
+
temp.close
|
26
|
+
assert_raise(IncludeException) do
|
27
|
+
inc = Includer.new(temp.path)
|
28
|
+
inc.readlines
|
29
|
+
inc.close
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_uri_include
|
34
|
+
make_include_file do |test_file|
|
35
|
+
inc = Includer.new(test_file.main_file)
|
36
|
+
lines = inc.readlines.map {|line| line.chomp}
|
37
|
+
assert_equal(['one-1', 'one-2', 'two-2', 'two-1'], lines)
|
38
|
+
inc.close
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_path
|
43
|
+
make_include_file do |test_file|
|
44
|
+
path = test_file.main_file
|
45
|
+
inc = Includer.new(test_file.main_file)
|
46
|
+
assert_equal(test_file.main_file, inc.path)
|
47
|
+
inc.close
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_each_byte
|
52
|
+
make_include_file do |test_file|
|
53
|
+
inc = Includer.new(test_file.main_file)
|
54
|
+
contents = inc.read.split(//)
|
55
|
+
inc.close
|
56
|
+
|
57
|
+
inc = Includer.new(test_file.main_file)
|
58
|
+
bytes = []
|
59
|
+
inc.each_byte do |b|
|
60
|
+
bytes << b.chr
|
61
|
+
end
|
62
|
+
inc.close
|
63
|
+
|
64
|
+
assert_equal(contents, bytes)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def make_include_file
|
71
|
+
temp1 = Tempfile.new('inctest')
|
72
|
+
temp2 = Tempfile.new('inctest')
|
73
|
+
|
74
|
+
temp2.write <<EOF2
|
75
|
+
one-2
|
76
|
+
two-2
|
77
|
+
EOF2
|
78
|
+
|
79
|
+
temp1.write <<EOF1
|
80
|
+
one-1
|
81
|
+
%include "#{temp2.path}"
|
82
|
+
two-1
|
83
|
+
EOF1
|
84
|
+
temp1.close
|
85
|
+
temp2.close
|
86
|
+
t = TestIncludeFile.new([temp1, temp2].map {|t| t.path})
|
87
|
+
if block_given?
|
88
|
+
begin
|
89
|
+
yield t
|
90
|
+
ensure
|
91
|
+
t.unlink
|
92
|
+
end
|
93
|
+
else
|
94
|
+
t
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class TestIncludeFile
|
100
|
+
attr_reader :main_file
|
101
|
+
|
102
|
+
def initialize(files)
|
103
|
+
@main_file = files[0]
|
104
|
+
@files = files
|
105
|
+
end
|
106
|
+
|
107
|
+
def unlink
|
108
|
+
@files.each do |f|
|
109
|
+
if File.exists? f
|
110
|
+
File.unlink f
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require '../test_helper'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'tmpdir'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'grizzled/fileutil'
|
7
|
+
|
8
|
+
include Grizzled::FileUtil
|
9
|
+
|
10
|
+
class MakeDirTreeTester < Test::Unit::TestCase
|
11
|
+
include GrizzledTestHelper
|
12
|
+
|
13
|
+
def test_make_directory_tree
|
14
|
+
tree = {"bmc" => {"moe" => {"a" => "aaaaaaaaaa",
|
15
|
+
"b" => "bbbbbbbbb"},
|
16
|
+
"larry" => "larry",
|
17
|
+
"curley" => "curley"}}
|
18
|
+
Dir.mktmpdir('ziptest') do |tmpdir|
|
19
|
+
make_directory_tree(tmpdir, tree)
|
20
|
+
|
21
|
+
# Now, reload the directory tree, and ensure that the tree
|
22
|
+
# matches what we created.
|
23
|
+
new_tree = {}
|
24
|
+
FileUtils.cd tmpdir do
|
25
|
+
new_tree = dir_to_hash "bmc"
|
26
|
+
end
|
27
|
+
|
28
|
+
assert_equal tree, new_tree
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def dir_to_hash(dir)
|
35
|
+
|
36
|
+
def load_dir_hash(dir)
|
37
|
+
h = {}
|
38
|
+
Dir.new(dir).entries.each do |dirent|
|
39
|
+
if dirent[0..0] != '.'
|
40
|
+
path = File.join(dir, dirent)
|
41
|
+
if File.directory? path
|
42
|
+
FileUtils.cd dir do
|
43
|
+
h[dirent] = load_dir_hash(dirent)
|
44
|
+
end
|
45
|
+
else
|
46
|
+
h[dirent] = File.open(path).read
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
h
|
51
|
+
end
|
52
|
+
|
53
|
+
{dir => load_dir_hash(dir)}
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require '../test_helper'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'tmpdir'
|
5
|
+
require 'grizzled/fileutil/ziputil'
|
6
|
+
|
7
|
+
include Grizzled::FileUtil::ZipUtil
|
8
|
+
|
9
|
+
class ZipMixinTestDriver < Test::Unit::TestCase
|
10
|
+
include GrizzledTestHelper
|
11
|
+
include ZipMixin, UnzipMixin
|
12
|
+
|
13
|
+
def test_zip_unzip_with_dir
|
14
|
+
with_tempfile('ziptest', '.zip') do |t|
|
15
|
+
|
16
|
+
# Create a zip file of the current directory
|
17
|
+
zip t.path, '.'
|
18
|
+
assert_equal(true, File.exists?(t.path))
|
19
|
+
|
20
|
+
# Now, unzip it and compare this file with its zipped-and-unzipped
|
21
|
+
# counterpart.
|
22
|
+
this_file_size = File.size(__FILE__)
|
23
|
+
this_file_contents = File.open(__FILE__).readlines.join('')
|
24
|
+
Dir.mktmpdir('ziptest') do |tmpdir|
|
25
|
+
unzip t.path, tmpdir
|
26
|
+
|
27
|
+
# File was unzipped under this directory name.
|
28
|
+
entry_dir = File.basename(File.dirname(File.expand_path(__FILE__)))
|
29
|
+
unzipped_this_file = File.join(tmpdir, entry_dir,
|
30
|
+
File.basename(__FILE__))
|
31
|
+
FileUtils.cd(tmpdir) do
|
32
|
+
assert_equal true, File.exists?(unzipped_this_file)
|
33
|
+
assert_equal this_file_size, File.size(unzipped_this_file)
|
34
|
+
contents = File.open(unzipped_this_file).readlines.join('')
|
35
|
+
assert_equal this_file_contents, contents
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_zip_unzip_without_dir
|
42
|
+
with_tempfile('ziptest', '.zip') do |t|
|
43
|
+
|
44
|
+
# Create a zip file of the current directory
|
45
|
+
zip t.path, '.', :dir_at_top => false
|
46
|
+
assert_equal(true, File.exists?(t.path))
|
47
|
+
|
48
|
+
# Now, unzip it and compare this file with its zipped-and-unzipped
|
49
|
+
# counterpart.
|
50
|
+
this_file_size = File.size(__FILE__)
|
51
|
+
this_file_contents = File.open(__FILE__).readlines.join('')
|
52
|
+
Dir.mktmpdir('ziptest') do |tmpdir|
|
53
|
+
unzip t.path, tmpdir
|
54
|
+
|
55
|
+
# File was unzipped in top level.
|
56
|
+
unzipped_this_file = File.join(tmpdir, File.basename(__FILE__))
|
57
|
+
FileUtils.cd(tmpdir) do
|
58
|
+
assert_equal true, File.exists?(unzipped_this_file)
|
59
|
+
assert_equal this_file_size, File.size(unzipped_this_file)
|
60
|
+
contents = File.open(unzipped_this_file).readlines.join('')
|
61
|
+
assert_equal this_file_contents, contents
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_non_recursive
|
68
|
+
expected_files = ['foo.txt', 'bar.txt']
|
69
|
+
Dir.mktmpdir 'ziptest' do |tmpdir|
|
70
|
+
FileUtils.cd tmpdir do
|
71
|
+
|
72
|
+
expected_files.each { |f| create_file(f, (f * 5) + "\n") }
|
73
|
+
|
74
|
+
# Now create a subdirectory.
|
75
|
+
Dir.mkdir 'subdir' do |subdir|
|
76
|
+
FileUtils.cd subdir do
|
77
|
+
# Create a couple more files which should NOT be zipped.
|
78
|
+
['moe', 'larry', 'curley'].each { |f| create_file(f, f) }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Now, zip up the temporary directory.
|
84
|
+
|
85
|
+
with_tempfile('ziptest', '.zip') do |t|
|
86
|
+
zip t.path, tmpdir, :dir_at_top => false, :recursive => false
|
87
|
+
|
88
|
+
assert_equal expected_files, zip_file_entries(t.path).to_a
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_zip_with_block
|
94
|
+
create_files = ['foo.txt', 'bar.txt']
|
95
|
+
expected_files = ['foo.txt']
|
96
|
+
|
97
|
+
Dir.mktmpdir 'ziptest' do |tmpdir|
|
98
|
+
FileUtils.cd tmpdir do
|
99
|
+
create_files.each { |f| create_file(f, (f * 5) + "\n") }
|
100
|
+
end
|
101
|
+
|
102
|
+
with_tempfile('ziptest', '.zip') do |t|
|
103
|
+
zip t.path, tmpdir, :dir_at_top => false, :recursive => false do |path|
|
104
|
+
expected_files.include? path
|
105
|
+
end
|
106
|
+
|
107
|
+
assert_equal expected_files, zip_file_entries(t.path).to_a
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_zip_file_entries
|
113
|
+
with_tempfile('ziptest', '.zip') do |t|
|
114
|
+
|
115
|
+
# Create a zip file of the current directory
|
116
|
+
zip t.path, '.', :dir_at_top => false, :recursive => false
|
117
|
+
assert_equal(true, File.exists?(t.path))
|
118
|
+
|
119
|
+
files_here = Dir.entries('.').select {|e| File.file? e}
|
120
|
+
entries = Hash[* files_here.map {|e| [e, 0]}.flatten]
|
121
|
+
|
122
|
+
zip_file_entries t.path do |e|
|
123
|
+
assert entries.has_key? e
|
124
|
+
entries[e] = 1
|
125
|
+
end
|
126
|
+
|
127
|
+
assert_equal 0, (entries.values.select {|v| v == 0}).length
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def create_file(path, contents)
|
134
|
+
f = File.open(path, 'w')
|
135
|
+
f.write(contents)
|
136
|
+
f.close
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require '../test_helper'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'grizzled/string/template'
|
4
|
+
|
5
|
+
include Grizzled::String::Template
|
6
|
+
|
7
|
+
module TemplateTestDriver
|
8
|
+
|
9
|
+
def do_safe_expansion(template_class, resolver, test_data)
|
10
|
+
u = template_class.new(resolver, :safe => true)
|
11
|
+
test_data.each do |string, expected, has_missing|
|
12
|
+
assert_equal(expected, u.substitute(string))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def do_unsafe_expansion(template_class, resolver, test_data)
|
17
|
+
u = template_class.new(resolver, :safe => false)
|
18
|
+
test_data.each do |string, expected, has_missing|
|
19
|
+
if has_missing
|
20
|
+
assert_raise(VariableNotFoundException) do
|
21
|
+
u.substitute(string)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class TestUnixShellStringTemplate < Test::Unit::TestCase
|
29
|
+
|
30
|
+
include TemplateTestDriver
|
31
|
+
|
32
|
+
RESOLVER = {"a" => "alpha", "foo" => "FOOBAR"}
|
33
|
+
TEST_DATA =
|
34
|
+
[
|
35
|
+
['${a} $foo ${b?bdef} $b ${foo}\$x', 'alpha FOOBAR bdef FOOBAR$x', true],
|
36
|
+
['\$a $foo $b', '$a FOOBAR ', true],
|
37
|
+
['$a', 'alpha', false]
|
38
|
+
]
|
39
|
+
|
40
|
+
def test_safe_expansion
|
41
|
+
do_safe_expansion(UnixShellStringTemplate, RESOLVER, TEST_DATA)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_unsafe_expansion
|
45
|
+
do_unsafe_expansion(UnixShellStringTemplate, RESOLVER, TEST_DATA)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class TestWindowsCmdStringTemplate < Test::Unit::TestCase
|
50
|
+
|
51
|
+
include TemplateTestDriver
|
52
|
+
|
53
|
+
RESOLVER = {"a" => "alpha", "foo" => "FOOBAR"}
|
54
|
+
TEST_DATA =
|
55
|
+
[
|
56
|
+
['%a% %foo% %b% %foo%\%x', 'alpha FOOBAR FOOBAR%x', true],
|
57
|
+
['\%a% %foo% %b%', '%a% FOOBAR ', true],
|
58
|
+
['%a%', 'alpha', false]
|
59
|
+
]
|
60
|
+
|
61
|
+
def test_safe_expansion
|
62
|
+
do_safe_expansion(WindowsCmdStringTemplate, RESOLVER, TEST_DATA)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_unsafe_expansion
|
66
|
+
do_unsafe_expansion(WindowsCmdStringTemplate, RESOLVER, TEST_DATA)
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'grizzled/forwarder'
|
5
|
+
|
6
|
+
class ForwarderTestDriver < Test::Unit::TestCase
|
7
|
+
|
8
|
+
class ForwardToFile
|
9
|
+
include Grizzled::Forwarder
|
10
|
+
|
11
|
+
def initialize(file, exceptions=[])
|
12
|
+
forward_to file, exceptions
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_forward_all
|
17
|
+
path = create_file
|
18
|
+
begin
|
19
|
+
contents = File.open(path).read
|
20
|
+
|
21
|
+
fwd = ForwardToFile.new(File.open(path))
|
22
|
+
contents2 = fwd.read
|
23
|
+
assert_equal(contents, contents2)
|
24
|
+
|
25
|
+
lines = []
|
26
|
+
fwd = ForwardToFile.new(File.open(path))
|
27
|
+
fwd.each_line do |line|
|
28
|
+
lines << line
|
29
|
+
end
|
30
|
+
contents2 = lines.join('')
|
31
|
+
assert_equal(contents, contents2)
|
32
|
+
ensure
|
33
|
+
File.unlink path
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_forward_all_but_each
|
38
|
+
path = create_file
|
39
|
+
begin
|
40
|
+
contents = File.open(path).read
|
41
|
+
|
42
|
+
fwd = ForwardToFile.new(File.open(path), [:each])
|
43
|
+
contents2 = fwd.read
|
44
|
+
assert_equal(contents, contents2)
|
45
|
+
|
46
|
+
assert_raise(NoMethodError) do
|
47
|
+
fwd.each
|
48
|
+
end
|
49
|
+
ensure
|
50
|
+
File.unlink path
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_forward_all_but_each_and_each_line
|
55
|
+
path = create_file
|
56
|
+
begin
|
57
|
+
contents = File.open(path).read
|
58
|
+
|
59
|
+
fwd = ForwardToFile.new(File.open(path), [:each, :each_line])
|
60
|
+
contents2 = fwd.read
|
61
|
+
assert_equal(contents, contents2)
|
62
|
+
|
63
|
+
assert_raise(NoMethodError) do
|
64
|
+
fwd.each do |c|
|
65
|
+
puts(c) # should not get here
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
assert_raise(NoMethodError) do
|
70
|
+
fwd.each_line do |line|
|
71
|
+
puts(line) # should not get here
|
72
|
+
end
|
73
|
+
end
|
74
|
+
ensure
|
75
|
+
File.unlink path
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def create_file
|
82
|
+
temp = Tempfile.new('fwdtest')
|
83
|
+
temp.write((1..80).to_a.join(', '))
|
84
|
+
temp.write((1..10).to_a.join(', '))
|
85
|
+
temp.close
|
86
|
+
temp.path
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
data/test/tc_stack.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'grizzled/stack'
|
4
|
+
|
5
|
+
include Grizzled
|
6
|
+
|
7
|
+
class StackTestDriver < Test::Unit::TestCase
|
8
|
+
|
9
|
+
def test_correct_class
|
10
|
+
assert_equal(Grizzled::Stack, Stack.new.class)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_underflow_no_exception
|
14
|
+
stack = Stack.new
|
15
|
+
assert_equal(nil, stack.pop)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_underflow_exception
|
19
|
+
stack = Stack.new(false)
|
20
|
+
assert_raise(StackUnderflowException) {stack.pop}
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_push
|
24
|
+
stack = Stack.new.push(5)
|
25
|
+
assert_equal([5], stack.to_a)
|
26
|
+
stack.push(10)
|
27
|
+
assert_equal([10, 5], stack.to_a)
|
28
|
+
stack.push(10)
|
29
|
+
assert_equal([10, 10, 5], stack.to_a)
|
30
|
+
stack.push([1, 2, 3])
|
31
|
+
assert_equal([3, 2, 1, 10, 10, 5], stack.to_a)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_length
|
35
|
+
stack = Stack.new.push(5)
|
36
|
+
assert_equal(1, stack.length)
|
37
|
+
|
38
|
+
stack.push(5)
|
39
|
+
assert_equal(2, stack.length)
|
40
|
+
|
41
|
+
stack.push((1..10).to_a)
|
42
|
+
assert_equal(12, stack.length)
|
43
|
+
|
44
|
+
stack.pop
|
45
|
+
assert_equal(11, stack.length)
|
46
|
+
|
47
|
+
stack.pop until stack.is_empty?
|
48
|
+
assert_equal(0, stack.length)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_clear
|
52
|
+
stack = Stack.new.push((1..10).to_a)
|
53
|
+
assert_equal(10, stack.length)
|
54
|
+
stack.clear
|
55
|
+
assert_equal(0, stack.length)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_pop_all
|
59
|
+
a = (1..10).to_a
|
60
|
+
stack = Stack.new.push(a)
|
61
|
+
assert_equal(10, stack.length)
|
62
|
+
a2 = stack.pop_all
|
63
|
+
assert_equal(0, stack.length)
|
64
|
+
assert_equal(a2, a.reverse)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_immutable
|
68
|
+
# Ensure that the to_a method doesn't return a stack that's
|
69
|
+
stack = Stack.new.push(5).push(10)
|
70
|
+
a = stack.to_a
|
71
|
+
assert_equal([10, 5], a)
|
72
|
+
a.pop
|
73
|
+
assert_equal([10, 5], stack.to_a)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_enumerable
|
77
|
+
stack = Stack.new.push([1, 2, 3])
|
78
|
+
assert_equal([3, 2, 1], stack.to_a)
|
79
|
+
a = []
|
80
|
+
stack.each {|element| a << element}
|
81
|
+
assert_equal(stack.to_a, a)
|
82
|
+
end
|
83
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grizzled-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 29
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 3
|
10
|
+
version: 0.1.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Brian M. Clapper
|
@@ -15,16 +15,16 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-03-
|
18
|
+
date: 2011-03-24 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
22
22
|
description: |
|
23
|
-
Grizzled Ruby is a general purpose library of Ruby modules and classes
|
23
|
+
Grizzled Ruby is a general purpose library of Ruby modules and classes.
|
24
24
|
|
25
25
|
email: bmc@clapper.org
|
26
|
-
executables:
|
27
|
-
|
26
|
+
executables:
|
27
|
+
- grinc
|
28
28
|
extensions: []
|
29
29
|
|
30
30
|
extra_rdoc_files: []
|
@@ -39,10 +39,17 @@ files:
|
|
39
39
|
- lib/grizzled/string/template.rb
|
40
40
|
- lib/grizzled/unix.rb
|
41
41
|
- lib/grizzled.rb
|
42
|
+
- test/tc_stack.rb
|
43
|
+
- test/tc_forwarder.rb
|
44
|
+
- test/fileutil/tc_zip.rb
|
45
|
+
- test/fileutil/tc_includer.rb
|
46
|
+
- test/fileutil/tc_make_dir_tree.rb
|
47
|
+
- test/string/tc_template.rb
|
48
|
+
- bin/grinc
|
42
49
|
has_rdoc: true
|
43
50
|
homepage: http://software.clapper.org/grizzled-ruby
|
44
|
-
licenses:
|
45
|
-
|
51
|
+
licenses:
|
52
|
+
- BSD
|
46
53
|
post_install_message:
|
47
54
|
rdoc_options: []
|
48
55
|
|
@@ -73,5 +80,10 @@ rubygems_version: 1.6.2
|
|
73
80
|
signing_key:
|
74
81
|
specification_version: 3
|
75
82
|
summary: Miscellaneous, general-purpose Ruby modules and classes
|
76
|
-
test_files:
|
77
|
-
|
83
|
+
test_files:
|
84
|
+
- test/tc_stack.rb
|
85
|
+
- test/tc_forwarder.rb
|
86
|
+
- test/fileutil/tc_zip.rb
|
87
|
+
- test/fileutil/tc_includer.rb
|
88
|
+
- test/fileutil/tc_make_dir_tree.rb
|
89
|
+
- test/string/tc_template.rb
|