grizzled-ruby 0.1.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.
@@ -0,0 +1,81 @@
1
+ # This software is released under a BSD license, adapted from
2
+ # http://opensource.org/licenses/bsd-license.php
3
+ #
4
+ # Copyright (c) 2011, Brian M. Clapper
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are
9
+ # met:
10
+ #
11
+ # * Redistributions of source code must retain the above copyright notice,
12
+ # this list of conditions and the following disclaimer.
13
+ #
14
+ # * Redistributions in binary form must reproduce the above copyright
15
+ # notice, this list of conditions and the following disclaimer in the
16
+ # documentation and/or other materials provided with the distribution.
17
+ #
18
+ # * Neither the names "clapper.org", "Grizzled Ruby Library", nor the
19
+ # names of its contributors may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
23
+ # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
26
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
+ # ---------------------------------------------------------------------------
34
+
35
+ # Grizzled Ruby: A library of miscellaneous, general-purpose Ruby modules.
36
+ #
37
+ # Author:: Brian M. Clapper (mailto:bmc@clapper.org)
38
+ # Copyright:: Copyright (c) 2011 Brian M. Clapper
39
+ # License:: BSD License
40
+ class Dir
41
+
42
+ # Adds a +walk+ method to the standard Ruby +Dir+ class. +walk+ walks a
43
+ # directory tree, starting at _dirname_, invoking the supplied block on
44
+ # each directory. The block is passed a +Dir+ object. The directory is
45
+ # walked top-down, not depth-first. To terminate the traversal, the block
46
+ # should return +false+. Anything else (including +nil+) continues the
47
+ # traversal.
48
+ def self.walk(dirname, &block)
49
+ Grizzled::Directory.walk(dirname, &block)
50
+ end
51
+
52
+ # Adds an +expand_path+ convenience method to the standard Ruby +Dir+
53
+ # class.
54
+ def expand_path
55
+ File.expand_path(self.path)
56
+ end
57
+ end
58
+
59
+ module Grizzled
60
+
61
+ # Useful directory-related methods.
62
+ class Directory
63
+
64
+ # Walk a directory tree, starting at _dirname_, invoking the supplied
65
+ # block on each directory. The block is passed a +Dir+ object. The
66
+ # directory is walked top-down, not depth-first. To terminate the
67
+ # traversal, the block should return +false+. Anything else (including
68
+ # +nil+) continues the traversal.
69
+ def self.walk(dirname, &block)
70
+ if block.call(Dir.new(dirname)) != false
71
+ Dir.entries(dirname).each do |entry|
72
+ path = File.join(dirname, entry)
73
+ if File.directory?(path) && (entry != '..') && (entry != '.')
74
+ Grizzled::Directory.walk(path, &block)
75
+ end
76
+ end
77
+ end
78
+ nil
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,241 @@
1
+ # Provides a file inclusion preprocessor. See the documentation for
2
+ # the Grizzled::FileUtil::Includer class for complete details.
3
+ #
4
+ # ---
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 'open-uri'
41
+ require 'uri'
42
+ require 'pathname'
43
+ require 'grizzled/forwarder'
44
+ require 'tempfile'
45
+
46
+ module Grizzled
47
+
48
+ module FileUtil
49
+
50
+ # Thrown when include file processing encounters errors.
51
+ class IncludeException < StandardError; end
52
+
53
+ # Internal container for source information.
54
+ class IncludeSource
55
+ URL_PATTERN = %r{^(http|https|ftp)://}
56
+
57
+ attr_reader :reader, :uri
58
+
59
+ def initialize(reader, uri)
60
+ @reader = reader
61
+ @uri = uri
62
+ end
63
+ end
64
+
65
+ # == Introduction
66
+ #
67
+ # An +Includer+ object preprocesses a text file, resolve _include_
68
+ # references. The +Includer+ is an +Enumerable+, allowing iteration over
69
+ # the lines of the resulting expanded file.
70
+ #
71
+ # == Include Syntax
72
+ #
73
+ # The _include_ syntax is defined by a regular expression; any line
74
+ # that matches the regular expression is treated as an _include_
75
+ # directive. The default regular expression matches include directives
76
+ # like this::
77
+ #
78
+ # %include "/absolute/path/to/file"
79
+ # %include "../relative/path/to/file"
80
+ # %include "local_reference"
81
+ # %include "http://localhost/path/to/my.config"
82
+ #
83
+ # Relative and local file references are relative to the including file
84
+ # or URL. That, if an +Includer+ is processing file "/home/bmc/foo.txt"
85
+ # and encounters an attempt to include file "bar.txt", it will assume
86
+ # "bar.txt" is to be found in "/home/bmc".
87
+ #
88
+ # Similarly, if an +Includer+ is processing URL
89
+ # "http://localhost/bmc/foo.txt" and encounters an attempt to include
90
+ # file "bar.txt", it will assume "bar.txt" is to be found at
91
+ # "http://localhost/bmc/bar.txt".
92
+ #
93
+ # Nested includes are permitted; that is, an included file may, itself,
94
+ # include other files. The maximum recursion level is configurable and
95
+ # defaults to 100.
96
+ #
97
+ # The include syntax can be changed by passing a different regular
98
+ # expression to the +Includer+ class constructor.
99
+ #
100
+ # == Supported Methods
101
+ #
102
+ # +Includer+ supports all the methods of the +File+ class and can be
103
+ # used the same way as a +File+ object is used.
104
+ #
105
+ # == Examples
106
+ #
107
+ # Preprocess a file containing include directives, then read the result:
108
+ #
109
+ # require 'grizzled/fileutil/includer'
110
+ # include Grizzled::FileUtil
111
+ #
112
+ # inc = Includer.new(path)
113
+ # inc.each do |line|
114
+ # puts(line)
115
+ # end
116
+ class Includer
117
+
118
+ include Enumerable
119
+ include Grizzled::Forwarder
120
+
121
+ attr_reader :name, :max_nesting
122
+
123
+ # Initialize a new +Includer+.
124
+ #
125
+ # Parameters:
126
+ #
127
+ # [+source+] A string, representing a file name or URL (http, https or
128
+ # ftp), a +File+ object, or an object with an +each_line+
129
+ # method that returns individual lines of input.
130
+ # [+options+] Various processing options. See below.
131
+ #
132
+ # Options:
133
+ #
134
+ # [+:max_nesting+] Maximum include nesting level. Default: 100
135
+ # [+:include_pattern+] String regex pattern to match include directives.
136
+ # Must have a single regex group for the file name
137
+ # or URL. Default: ^%include\s"([^"]+)"
138
+ def initialize(source, options={})
139
+ @max_nesting = options.fetch(:max_nesting, 100)
140
+ inc_pattern = options.fetch(:include_pattern, '^%include\s"([^"]+)"')
141
+ @include_re = /#{inc_pattern}/
142
+ includer_source = source_to_includer_source source
143
+ @source_uri = includer_source.uri
144
+ @temp = preprocess includer_source
145
+ @input = File.open @temp.path
146
+ forward_to @input
147
+ end
148
+
149
+ # Return the path of the original include file, if defined. If the
150
+ # original source was a URL, the URL is returned. If the source was a
151
+ # string, nil is returned.
152
+ def path
153
+ @source_uri.path
154
+ end
155
+
156
+ # Force the underlying resource to be closed.
157
+ def close
158
+ @input.close
159
+ @temp.unlink
160
+ end
161
+
162
+ private
163
+
164
+ def source_to_includer_source(source)
165
+ if source.class == String
166
+ open_source(URI::parse(source))
167
+ elsif source.class == File
168
+ open_source(URI::parse(source.path))
169
+ elsif source.respond_to? :each_line
170
+ IncludeSource.new(source, nil)
171
+ else
172
+ raise IncludeException.new("Bad input of class #{source.class}")
173
+ end
174
+ end
175
+
176
+ def preprocess(includer_source)
177
+
178
+ def do_read(input, temp, level)
179
+ input.reader.each_line do |line|
180
+ if m = @include_re.match(line)
181
+ if level >= @max_nesting
182
+ raise IncludeException.new("Too many nested includes " +
183
+ "(#{level.to_s}), at: " +
184
+ "\"#{line.chomp}\"")
185
+ end
186
+ new_input = process_include(m[1], input)
187
+ do_read(new_input, temp, level + 1)
188
+ else
189
+ temp.write(line)
190
+ end
191
+ end
192
+ end
193
+
194
+
195
+ temp = Tempfile.new('grizzled_includer')
196
+ begin
197
+ do_read(includer_source, temp, 1)
198
+ ensure
199
+ temp.close
200
+ end
201
+
202
+ temp
203
+ end
204
+
205
+ # Handle an include reference.
206
+ def process_include(source, parent_input)
207
+ cur_uri = parent_input.uri
208
+ uri = URI::parse(source)
209
+ if (cur_uri != nil) and (uri.scheme == nil)
210
+ # Could be a relative path. Should be relative to the parent input.
211
+ pathname = Pathname.new(source)
212
+ if not pathname.absolute?
213
+ # Not an absolute path, and the including source has a path
214
+ # (i.e., wasn't a string). Make this one relative to the path.
215
+ uri = cur_uri.clone
216
+ uri.path = File.join(::File.dirname(cur_uri.path), source)
217
+ end
218
+ end
219
+
220
+ open_source(uri)
221
+ end
222
+
223
+ # Open an input source, based on a parsed URI.
224
+ def open_source(uri)
225
+ case uri.scheme
226
+ when nil then f = open(uri.path) # assume file/path
227
+ when 'file' then f = open(uri.path) # open path directly
228
+ when 'http' then f = open(uri.to_s) # open-uri will handle it
229
+ when 'https' then f = open(uri.to_s) # open-uri will handle it
230
+ when 'ftp' then f = open(uri.to_s) # open-uri will handle it
231
+
232
+ else raise IncludeException.new("Don't know how to open #{uri.to_s}")
233
+ end
234
+
235
+ IncludeSource.new(f, uri)
236
+ end
237
+ end # class Includer
238
+
239
+ end # module File
240
+ end # module Grizzled
241
+
@@ -0,0 +1,91 @@
1
+ # Provides a module which, when mixed in, can be used to forward all
2
+ # missing methods to another object.
3
+ #
4
+ # ---
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
+ module Grizzled
41
+
42
+ # +Forwarder+ makes it easy to forward calls to another object.
43
+ #
44
+ # Examples:
45
+ #
46
+ # Forward all unimplemented methods to a file:
47
+ #
48
+ # class Test
49
+ # include Grizzled::Forwarder
50
+ #
51
+ # def initialize(file)
52
+ # forward_to file
53
+ # end
54
+ # end
55
+ #
56
+ # Test.new(File.open('/tmp/foobar')).each_line do |line|
57
+ # puts(line)
58
+ # end
59
+ #
60
+ # Forward all unimplemented calls, _except_ +each+ to the specified
61
+ # object. Calls to +each+ will raise a +NoMethodError+:
62
+ #
63
+ # class Test
64
+ # include Grizzled::Forwarder
65
+ #
66
+ # def initialize(file)
67
+ # forward_to file, [:each]
68
+ # end
69
+ # end
70
+ module Forwarder
71
+
72
+ # Forward all unimplemented method calls to +obj+, except those
73
+ # whose symbols are listed in the +exceptions+ array.
74
+ def forward_to(obj, exceptions=[])
75
+ @forward_obj = obj
76
+
77
+ require 'set'
78
+
79
+ @forwarder_exceptions = Set.new(exceptions)
80
+ class << self
81
+ def method_missing(m, *args, &block)
82
+ if not @forwarder_exceptions.include? m
83
+ @forward_obj.send(m, *args, &block)
84
+ else
85
+ super(m, *args, &block)
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,159 @@
1
+ # Provides a simple stack implementation. See the Grizzled::Stack class
2
+ # for complete details.
3
+ #
4
+ # ---
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
+ # Grizzled Ruby: A library of miscellaneous, general-purpose Ruby modules.
41
+ #
42
+ # Author:: Brian M. Clapper (mailto:bmc@clapper.org)
43
+ # Copyright:: Copyright (c) 2011 Brian M. Clapper
44
+ # License:: BSD License
45
+ module Grizzled
46
+
47
+ # Thrown for un-safe stacks if the stack
48
+ class StackUnderflowException < StandardError; end
49
+
50
+ # A simple stack wrapper on top of a Ruby array, providing a little more
51
+ # protection that using an array directly.
52
+ class Stack
53
+
54
+ include Enumerable
55
+
56
+ attr_reader :pop_empty_nil
57
+
58
+ # Initialize a new stack.
59
+ #
60
+ # Parameters:
61
+ #
62
+ # [+pop_empty_nil+] +true+ if popping an empty stack should just return
63
+ # +nil+, +false+ if it should thrown an exception.
64
+ def initialize(pop_empty_nil=true)
65
+ @the_stack = []
66
+ @pop_empty_nil = pop_empty_nil
67
+ end
68
+
69
+ # Pop the top element from the stack. If the stack is empty, this method
70
+ # throws a +StackUnderflowException+, if +pop_empty_nil+ is +false+; or
71
+ # returns nil, if +pop_empty_nil+ is +true+.
72
+ def pop
73
+ if (@the_stack.length == 0) && (not @pop_empty_nil)
74
+ raise StackUnderflowException.new
75
+ end
76
+ @the_stack.pop
77
+ end
78
+
79
+ # Pop every element of the stack, returning the results as an array
80
+ # and clearing the stack.
81
+ def pop_all
82
+ result = @the_stack.reverse
83
+ @the_stack.clear
84
+ result
85
+ end
86
+
87
+ # Convenience method for +length == 0+.
88
+ def is_empty?
89
+ length == 0
90
+ end
91
+
92
+ # Push an element or an array of elements onto the stack. Returns the
93
+ # stack itself, to allow chaining. Note: If you push an array of elements,
94
+ # the elements end up being reversed on the stack. That is, this:
95
+ #
96
+ # stack = Stack.new.push([1, 2, 3]) # yields Stack[3, 2, 1]
97
+ #
98
+ # is equivalent to
99
+ #
100
+ # stack = Stack.new
101
+ # [1, 2, 3].each {|i| stack.push i}
102
+ def push(element)
103
+ if element.class == Array
104
+ element.each {|e| @the_stack.push e}
105
+ else
106
+ @the_stack.push element
107
+ end
108
+ self
109
+ end
110
+
111
+ # Returns the size of the stack.
112
+ def length
113
+ @the_stack.length
114
+ end
115
+
116
+ # Yield each element of the stack, in turn. Unaffected by a change in
117
+ # the stack.
118
+ def each
119
+ self.to_a.each do |element|
120
+ yield element
121
+ end
122
+ end
123
+
124
+ # Clear the stack. Returns the stack, for chaining.
125
+ def clear
126
+ @the_stack.clear
127
+ self
128
+ end
129
+
130
+ # Printable version.
131
+ def inspect
132
+ @the_stack.inspect
133
+ end
134
+
135
+ # Return the stack as an array.
136
+ def to_a
137
+ @the_stack.reverse
138
+ end
139
+
140
+ # Return the stack's hash.
141
+ def hash
142
+ @the_stack.hash
143
+ end
144
+
145
+ # Determine if this hash is equal to another one.
146
+ def eql?(other)
147
+ (other.class == Stack) and (other.to_a == to_a)
148
+ end
149
+
150
+ # Compare this stack to another element.
151
+ def <=>(other)
152
+ if other.class == Stack
153
+ other.to_a <=> to_a
154
+ else
155
+ other.to_s <=> this.to_s
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,416 @@
1
+ # Provides a simple variable substitution capability, similar, in concept,
2
+ # to Python's +StringTemplate+ class. See the Grizzled::String::Template
3
+ # module, the Grizzled::String::UnixShellStringTemplate class and the
4
+ # Grizzled::String::WindowsCmdStringTemplate class for complete details.
5
+ #
6
+ # ---
7
+ #
8
+ # This software is released under a BSD license, adapted from
9
+ # http://opensource.org/licenses/bsd-license.php
10
+ #
11
+ # Copyright (c) 2011, Brian M. Clapper
12
+ # All rights reserved.
13
+ #
14
+ # Redistribution and use in source and binary forms, with or without
15
+ # modification, are permitted provided that the following conditions are
16
+ # met:
17
+ #
18
+ # * Redistributions of source code must retain the above copyright notice,
19
+ # this list of conditions and the following disclaimer.
20
+ #
21
+ # * Redistributions in binary form must reproduce the above copyright
22
+ # notice, this list of conditions and the following disclaimer in the
23
+ # documentation and/or other materials provided with the distribution.
24
+ #
25
+ # * Neither the names "clapper.org", "Grizzled Ruby Library", nor the
26
+ # names of its contributors may be used to endorse or promote products
27
+ # derived from this software without specific prior written permission.
28
+ #
29
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
30
+ # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
31
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
33
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
34
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
36
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
37
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
+ # ---------------------------------------------------------------------------
41
+
42
+ # Grizzled Ruby: A library of miscellaneous, general-purpose Ruby modules.
43
+ #
44
+ # Author:: Brian M. Clapper (mailto:bmc@clapper.org)
45
+ # Copyright:: Copyright (c) 2011 Brian M. Clapper
46
+ # License:: BSD License
47
+ module Grizzled
48
+
49
+ module String
50
+
51
+ # Grizzled::String::Template - A simple string templating solution
52
+ # modeled after Python's +StringTemplate+ library. While Ruby has less
53
+ # need of this kind of library, because of its built-in string
54
+ # interpolation, this module can be useful for interoperating with
55
+ # Python or with the Grizzled Scala library's string templating
56
+ # library.
57
+ module Template
58
+
59
+ # Exception raised for non-existent variables in non-safe templates.
60
+ class VariableNotFoundException < StandardError; end
61
+
62
+ # What a parsed variable looks like.
63
+ class Variable
64
+
65
+ attr_reader :istart, :iend, :name, :default
66
+
67
+ def initialize(istart, iend, name, default=nil)
68
+ @istart = istart
69
+ @iend = iend
70
+ @name = name
71
+ @default = default
72
+ end
73
+
74
+ alias :inspect :to_s
75
+ def to_s
76
+ "#{name}"
77
+ end
78
+ end
79
+
80
+ # Base (abstract) class for a string template. Common logic is here.
81
+ # Subclasses implement specific methods.
82
+ class TemplateBase
83
+
84
+ attr_reader :resolver, :safe
85
+
86
+ # Initializer.
87
+ #
88
+ # Parameters:
89
+ #
90
+ # [+resolver+] A hash-like object that can take a variable name (via
91
+ # the +[]+ function) and resolve its value, returning
92
+ # the value (which is converted to string) or +nil+.
93
+ # [+options+] hash of options. See below.
94
+ #
95
+ # Options:
96
+ #
97
+ # [+:safe+] +true+ for a safe template that substitutes a blank
98
+ # string for a non-existent variable, instead of
99
+ # throwing an exception. Defaults to +true+.
100
+ def initialize(resolver, options={})
101
+ @resolver = resolver
102
+ @safe = options.fetch(:safe, true)
103
+ end
104
+
105
+ # Replace all variable references in the given string. Variable
106
+ # references are recognized per the regular expression passed to
107
+ # the constructor. If a referenced variable is not found in the
108
+ # resolver, this method either:
109
+ #
110
+ # - throws a +VariableNotFoundException+ (if +safe+ is +false+).
111
+ # - substitutes an empty string (if +safe+ is +true+)
112
+ #
113
+ # Recursive references are supported (but beware of infinite recursion).
114
+ #
115
+ # Parameters:
116
+ #
117
+ # [+s+] the string in which to replace variable references
118
+ #
119
+ # Returns the substituted result.
120
+ def substitute(s)
121
+
122
+ def substitute_variable(var, s)
123
+ end_string = var.iend == s.length ? "" : s[var.iend..-1]
124
+ value = get_variable(var.name, var.default)
125
+ transformed =
126
+ (var.istart == 0 ? "" : s[0..(var.istart-1)]) + value + end_string
127
+ substitute(transformed)
128
+ end
129
+
130
+ # Locate the next variable reference.
131
+ var = find_variable_ref(s)
132
+ if var.nil?
133
+ s
134
+ else
135
+ substitute_variable(var, s)
136
+ end
137
+ end
138
+
139
+ # Parse the location of the first variable in the string. Subclasses
140
+ # should override this method.
141
+ #
142
+ # Parameters:
143
+ #
144
+ # [+s+] the string
145
+ #
146
+ # Returns a +Variable+ object, or +nil+.
147
+ def find_variable_ref(s)
148
+ nil
149
+ end
150
+
151
+ # Get a variable's value, returning the empty string or throwing an
152
+ # exception, depending on the setting of +safe+.
153
+ #
154
+ # Parameters:
155
+ #
156
+ # [+name+] Variable name
157
+ # [+default+] Default value, or +nil+
158
+ def get_variable(name, default)
159
+
160
+ def handle_no_value(default, name)
161
+ if not default.nil?
162
+ default
163
+ elsif @safe
164
+ ""
165
+ else
166
+ raise VariableNotFoundException.new(name)
167
+ end
168
+ end
169
+
170
+ resolver[name] || handle_no_value(default, name)
171
+ end
172
+ end # TemplateBase
173
+
174
+ # A string template that uses the Unix shell-like syntax +${varname}+
175
+ # (or +$varname+) for variable references. A variable's name typically
176
+ # consists of alphanumerics and underscores, but is controlled by the a
177
+ # supplied regular expression. To include a literal "$" in a string,
178
+ # escape it with a backslash.
179
+ #
180
+ # For this class, the general form of a variable reference is:
181
+ #
182
+ # ${varname?default}
183
+ #
184
+ # The +?default+ suffix is optional and specifies a default value
185
+ # to be used if the variable has no value.
186
+ #
187
+ # A shorthand form of a variable reference is:
188
+ #
189
+ # $varname
190
+ #
191
+ # The _default_ capability is not available in the shorthand form.
192
+ class UnixShellStringTemplate < TemplateBase
193
+
194
+ ESCAPED_DOLLAR_PLACEHOLDER = "\001"
195
+ ESCAPED_DOLLAR = %r{(\\*)(\\\$)}
196
+
197
+ # Initialize a new +UnixShellStringTemplate+. Supports various hash
198
+ # options.
199
+ #
200
+ # Parameters:
201
+ #
202
+ # [+resolver+] A hash-like object that can take a variable name (via
203
+ # the +[]+ function) and resolve its value, returning
204
+ # the value (which is converted to string) or +nil+.
205
+ # [+options+] hash of options. See below.
206
+ #
207
+ # Options:
208
+ #
209
+ # [+:safe+] +true+ for a safe template that substitutes a blank
210
+ # string for a non-existent variable, instead of
211
+ # throwing an exception. Defaults to +true+.
212
+ # [+:var_pattern+] Regular expression pattern (as a string, not a
213
+ # Regexp object) to match a variable name. Defaults
214
+ # to "[A-Za-z0-9_]+"
215
+ def initialize(resolver, options={})
216
+ super(resolver, options)
217
+ var_re = options.fetch(:var_pattern, "[A-Za-z0-9_]+")
218
+ @long_var_regexp = %r{\$\{(#{var_re})(\?[^\}]*)?\}}
219
+ @short_var_regexp = %r{\$(#{var_re})}
220
+ end
221
+
222
+ # Replace all variable references in the given string. Variable
223
+ # references are recognized per the regular expression passed to
224
+ # the constructor. If a referenced variable is not found in the
225
+ # resolver, this method either:
226
+ #
227
+ # - throws a +VariableNotFoundException+ (if +safe+ is +false+).
228
+ # - substitutes an empty string (if +safe+ is +true+)
229
+ #
230
+ # Recursive references are supported (but beware of infinite recursion).
231
+ #
232
+ # Parameters:
233
+ #
234
+ # [+s+] the string in which to replace variable references
235
+ #
236
+ # Returns the substituted result.
237
+ def substitute(s)
238
+ # Kludge to handle escaped "$". Temporarily replace it with
239
+ # something highly unlikely to be in the string. Then, put a single
240
+ # "$" in its place, after the substitution. Must be sure to handle
241
+ # even versus odd number of backslash characters.
242
+
243
+ def pre_sub(s)
244
+
245
+ def handle_match(m, s)
246
+ if (m[1].length % 2) == 0
247
+ # Odd number of backslashes before "$", including
248
+ # the one with the dollar token (group 2). Valid escape.
249
+
250
+ b = m.begin(0)
251
+ start = (b == 0 ? "" : s[0..(b-1)])
252
+ start + ESCAPED_DOLLAR_PLACEHOLDER + pre_sub(s[m.end(0)..-1])
253
+ else
254
+ # Even number of backslashes before "$", including the one
255
+ # with the dollar token (group 2). Not an escape.
256
+ s
257
+ end
258
+ end
259
+
260
+ # Check for an escaped "$"
261
+ m = ESCAPED_DOLLAR.match(s)
262
+ if (m)
263
+ handle_match(m, s)
264
+ else
265
+ s
266
+ end
267
+ end
268
+
269
+ s2 = super(pre_sub(s))
270
+ s2.gsub(ESCAPED_DOLLAR_PLACEHOLDER, '$')
271
+ end
272
+
273
+ # Parse the location of the first variable in the string. Subclasses
274
+ # should override this method.
275
+ #
276
+ # Parameters:
277
+ #
278
+ # [+s+] the string
279
+ #
280
+ # Returns a +Variable+ object, or +nil+.
281
+ def find_variable_ref(s)
282
+
283
+ def handle_long_match(m)
284
+ name = m[1]
285
+ if m[2].nil?
286
+ default = nil
287
+ else
288
+ # Pull off the "?"
289
+ default = m[2][1..-1]
290
+ end
291
+
292
+ Variable.new(m.begin(0), m.end(0), name, default)
293
+ end
294
+
295
+ def handle_no_long_match(s)
296
+ m = @short_var_regexp.match(s)
297
+ if m.nil?
298
+ nil
299
+ else
300
+ Variable.new(m.begin(0), m.end(0), m[1], nil)
301
+ end
302
+ end
303
+
304
+ m = @long_var_regexp.match(s)
305
+ if m.nil?
306
+ handle_no_long_match(s)
307
+ else
308
+ handle_long_match(m)
309
+ end
310
+ end
311
+
312
+ end # UnixShellStringTemplate
313
+
314
+ # A string template that uses the Windows +cmd.exe+ syntax +%varname%+
315
+ # for variable references. A variable's name may consist of alphanumerics
316
+ # and underscores. To include a literal "%" in a string, escape it with
317
+ # a backslash ("\%").
318
+ class WindowsCmdStringTemplate < TemplateBase
319
+
320
+ ESCAPED_PERCENT = %r{(\\*)(%)}
321
+ ESCAPED_PERCENT_PLACEHOLDER = '\001'
322
+
323
+ # Initialize a new +WindowsCmdStringTemplate+. Supports various hash
324
+ # options.
325
+ #
326
+ # Parameters:
327
+ #
328
+ # [+resolver+] A hash-like object that can take a variable name (via
329
+ # the +[]+ function) and resolve its value, returning
330
+ # the value (which is converted to string) or +nil+.
331
+ # [+options+] hash of options. See below.
332
+ #
333
+ # Options:
334
+ #
335
+ # [+:safe+] +true+ for a safe template that substitutes a blank
336
+ # string for a non-existent variable, instead of
337
+ # throwing an exception. Defaults to +true+.
338
+ # [+:var_pattern+] Regular expression pattern (as a string, not a
339
+ # Regexp object) to match a variable name. Defaults
340
+ # to "[A-Za-z0-9_]+"
341
+ def initialize(resolver, options={})
342
+ super(resolver, options)
343
+ var_pat = options.fetch(:var_pattern, "[A-Za-z0-9_]+")
344
+ @var_re = %r{%(#{var_pat})%}
345
+ end
346
+
347
+ # Replace all variable references in the given string. Variable
348
+ # references are recognized per the regular expression passed to
349
+ # the constructor. If a referenced variable is not found in the
350
+ # resolver, this method either:
351
+ #
352
+ # - throws a +VariableNotFoundException+ (if +safe+ is +false+).
353
+ # - substitutes an empty string (if +safe+ is +true+)
354
+ #
355
+ # Recursive references are supported (but beware of infinite recursion).
356
+ #
357
+ # Parameters:
358
+ #
359
+ # [+s+] the string in which to replace variable references
360
+ #
361
+ # Returns the substituted result.
362
+ def substitute(s)
363
+ # Kludge to handle escaped "%". Temporarily replace it with
364
+ # something highly unlikely to be in the string. Then, put a single
365
+ # "%" in its place, after the substitution. Must be sure to handle
366
+ # even versus odd number of backslash characters.
367
+
368
+ def pre_sub(s)
369
+
370
+ def handle_match(m, s)
371
+ if (m[1].length % 2) == 1
372
+ # Odd number of backslashes before "%". Valid escape.
373
+
374
+ b = m.begin(0)
375
+ start = (b == 0 ? "" : s[0..(b-1)])
376
+ start + ESCAPED_PERCENT_PLACEHOLDER + pre_sub(s[m.end(0)..-1])
377
+ else
378
+ # Even number of backslashes before "%". Not an escape.
379
+ s
380
+ end
381
+ end
382
+
383
+ # Check for an escaped "%"
384
+ m = ESCAPED_PERCENT.match(s)
385
+ if (m)
386
+ handle_match(m, s)
387
+ else
388
+ s
389
+ end
390
+ end
391
+
392
+ s2 = super(pre_sub(s))
393
+ s2.gsub(ESCAPED_PERCENT_PLACEHOLDER, '%')
394
+ end
395
+
396
+ # Parse the location of the first variable in the string. Subclasses
397
+ # should override this method.
398
+ #
399
+ # Parameters:
400
+ #
401
+ # [+s+] the string
402
+ #
403
+ # Returns a +Variable+ object, or +nil+.
404
+ def find_variable_ref(s)
405
+ m = @var_re.match(s)
406
+ if m.nil?
407
+ nil
408
+ else
409
+ Variable.new(m.begin(0), m.end(0), m[1], nil)
410
+ end
411
+ end
412
+ end # WindowsCmdStringTemplate
413
+
414
+ end # module
415
+ end # module
416
+ end
@@ -0,0 +1,89 @@
1
+ # This software is released under a BSD license, adapted from
2
+ # http://opensource.org/licenses/bsd-license.php
3
+ #
4
+ # Copyright (c) 2011, Brian M. Clapper
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are
9
+ # met:
10
+ #
11
+ # * Redistributions of source code must retain the above copyright notice,
12
+ # this list of conditions and the following disclaimer.
13
+ #
14
+ # * Redistributions in binary form must reproduce the above copyright
15
+ # notice, this list of conditions and the following disclaimer in the
16
+ # documentation and/or other materials provided with the distribution.
17
+ #
18
+ # * Neither the names "clapper.org", "Grizzled Ruby Library", nor the
19
+ # names of its contributors may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
23
+ # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
26
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
+ # ---------------------------------------------------------------------------
34
+
35
+ # Grizzled Ruby: A library of miscellaneous, general-purpose Ruby modules.
36
+ #
37
+ # Author:: Brian M. Clapper (mailto:bmc@clapper.org)
38
+ # Copyright:: Copyright (c) 2011 Brian M. Clapper
39
+ # License:: BSD License
40
+ module Grizzled
41
+
42
+ # Unix-related OS things.
43
+ module Unix
44
+
45
+ # A +User+ object allows you to do things with Unix users, such as
46
+ # (for instance) run code as that user.
47
+ class User
48
+
49
+ require 'etc'
50
+
51
+ # Initialize a new user. The +id+ parameter is either a user name
52
+ # (string) or a UID (integer).
53
+ def initialize(id)
54
+ # Find the user in the password database.
55
+ @pwent = (id.is_a? Integer) ? Etc.getpwuid(id) : Etc.getpwnam(id)
56
+ end
57
+
58
+ # Run a block of code as this user.
59
+ #
60
+ # [+block+] the block to execute as that user. It will receive this
61
+ # +User+ object as a parameter.
62
+ #
63
+ # This function will only run as 'root'.
64
+ #
65
+ # === Example
66
+ #
67
+ # require 'grizzled/unix'
68
+ # require 'fileutils'
69
+ #
70
+ # Grizzled::Unix::User.new('root').run_as |u|
71
+ # rm_r(File.join('/tmp', '*')) # Yeah, this is dangerous
72
+ # end
73
+ def run_as(&block)
74
+
75
+ # Fork the child process. Process.fork will run a given block of
76
+ # code in the child process.
77
+ child = Process.fork do
78
+ # We're in the child. Set the process's user ID.
79
+ Process.uid = @pwent.uid
80
+
81
+ # Invoke the caller's block of code.
82
+ block.call(self)
83
+ end
84
+
85
+ Process.waitpid(child)
86
+ end
87
+ end
88
+ end
89
+ end
data/lib/grizzled.rb ADDED
@@ -0,0 +1,42 @@
1
+ # Grizzled Ruby is a library of miscellaneous Ruby classes and modules.
2
+ # See http://software.clapper.org/grizzled-ruby/ for more details.
3
+ #
4
+ # Author:: Brian M. Clapper (mailto:bmc@clapper.org)
5
+ # Copyright:: Copyright (c) 2011 Brian M. Clapper
6
+ # License:: BSD License
7
+ #
8
+ # ---
9
+ #
10
+ # This software is released under a BSD license, adapted from
11
+ # http://opensource.org/licenses/bsd-license.php
12
+ #
13
+ # Copyright (c) 2011, Brian M. Clapper
14
+ # All rights reserved.
15
+ #
16
+ # Redistribution and use in source and binary forms, with or without
17
+ # modification, are permitted provided that the following conditions are
18
+ # met:
19
+ #
20
+ # * Redistributions of source code must retain the above copyright notice,
21
+ # this list of conditions and the following disclaimer.
22
+ #
23
+ # * Redistributions in binary form must reproduce the above copyright
24
+ # notice, this list of conditions and the following disclaimer in the
25
+ # documentation and/or other materials provided with the distribution.
26
+ #
27
+ # * Neither the names "clapper.org", "Grizzled Ruby Library", nor the
28
+ # names of its contributors may be used to endorse or promote products
29
+ # derived from this software without specific prior written permission.
30
+ #
31
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
32
+ # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
33
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
35
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
36
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
37
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
38
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
39
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42
+ # ---------------------------------------------------------------------------
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: grizzled-ruby
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Brian M. Clapper
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-12 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: |
23
+ Grizzled Ruby is a general purpose library of Ruby modules and classes
24
+
25
+ email: bmc@clapper.org
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - lib/grizzled/stack.rb
34
+ - lib/grizzled/fileutil/includer.rb
35
+ - lib/grizzled/dir.rb
36
+ - lib/grizzled/forwarder.rb
37
+ - lib/grizzled/string/template.rb
38
+ - lib/grizzled/unix.rb
39
+ - lib/grizzled.rb
40
+ has_rdoc: true
41
+ homepage: http://software.clapper.org/grizzled-ruby
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ hash: 3
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ hash: 3
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ requirements: []
68
+
69
+ rubyforge_project:
70
+ rubygems_version: 1.6.2
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Miscellaneous, general-purpose Ruby modules and classes
74
+ test_files: []
75
+