glue 0.13.0 → 0.14.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,23 @@
1
+ #!/usr/local/bin/ruby -w
2
+ #
3
+ # == extensions/hash.rb
4
+ #
5
+ # Adds methods to the builtin Hash class.
6
+ #
7
+
8
+ require "extensions/_base"
9
+
10
+ #
11
+ # * Hash#select!
12
+ #
13
+ ExtensionsProject.implement(Hash, :select!) do
14
+ class Hash
15
+ #
16
+ # In-place version of Hash#select. (Counterpart to, and opposite of, the
17
+ # built-in #reject!)
18
+ #
19
+ def select!
20
+ reject! { |k,v| not yield(k,v) }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,58 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ #
4
+ # == extensions/io.rb
5
+ #
6
+ # Adds methods to the builtin IO class.
7
+ #
8
+
9
+ require "extensions/_base"
10
+
11
+ # This is Ruby's built-in IO class.
12
+ class IO
13
+ end
14
+
15
+ #
16
+ # * IO.write
17
+ #
18
+ ExtensionsProject.implement(IO, :write, :class) do
19
+ class << IO
20
+ #
21
+ # Writes the given data to the given path and closes the file. This is
22
+ # done in binary mode, complementing <tt>IO.read</tt> in standard Ruby.
23
+ #
24
+ # Returns the number of bytes written.
25
+ #
26
+ def write(path, data)
27
+ File.open(path, "wb") do |file|
28
+ return file.write(data)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ #
35
+ # * IO.writelines
36
+ #
37
+ ExtensionsProject.implement(IO, :writelines, :class) do
38
+ class << IO
39
+ #
40
+ # Writes the given array of data to the given path and closes the file.
41
+ # This is done in binary mode, complementing <tt>IO.readlines</tt> in
42
+ # standard Ruby.
43
+ #
44
+ # Note that +readlines+ (the standard Ruby method) returns an array of lines
45
+ # <em>with newlines intact</em>, whereas +writelines+ uses +puts+, and so
46
+ # appends newlines if necessary. In this small way, +readlines+ and
47
+ # +writelines+ are not exact opposites.
48
+ #
49
+ # Returns +nil+.
50
+ #
51
+ def writelines(path, data)
52
+ File.open(path, "wb") do |file|
53
+ file.puts(data)
54
+ end
55
+ end
56
+ end
57
+ end
58
+
@@ -0,0 +1,42 @@
1
+ #!/usr/local/bin/ruby -w
2
+ #
3
+ # == extensions/module.rb
4
+ #
5
+ # Adds methods to the builtin Kernel module.
6
+ #
7
+
8
+ require "extensions/_base"
9
+
10
+ ExtensionsProject.implement(Kernel, :require_relative) do
11
+ module Kernel
12
+ #
13
+ # <tt>require_relative</tt> complements the builtin method <tt>require</tt> by allowing
14
+ # you to load a file that is <em>relative to the file containing the require_relative
15
+ # statement</em>.
16
+ #
17
+ # When you use <tt>require</tt> to load a file, you are usually accessing functionality
18
+ # that has been properly installed, and made accessible, in your system. <tt>require</tt>
19
+ # does not offer a good solution for loading files within the project's code. This may
20
+ # be useful during a development phase, for accessing test data, or even for accessing
21
+ # files that are "locked" away inside a project, not intended for outside use.
22
+ #
23
+ # For example, if you have unit test classes in the "test" directory, and data for them
24
+ # under the test "test/data" directory, then you might use a line like this in a test
25
+ # case:
26
+ #
27
+ # require_relative "data/customer_data_1"
28
+ #
29
+ # Since neither "test" nor "test/data" are likely to be in Ruby's library path (and for
30
+ # good reason), a normal <tt>require</tt> won't find them. <tt>require_relative</tt> is
31
+ # a good solution for this particular problem.
32
+ #
33
+ # You may include or omit the extension (<tt>.rb</tt> or <tt>.so</tt>) of the file you
34
+ # are loading.
35
+ #
36
+ # _path_ must respond to <tt>to_str</tt>.
37
+ #
38
+ def require_relative(path)
39
+ require File.join(File.dirname(caller[0]), path.to_str)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,114 @@
1
+ #!/usr/local/bin/ruby -w
2
+ #
3
+ # == extensions/module.rb
4
+ #
5
+ # Adds methods to the builtin Module class.
6
+ #
7
+
8
+ require "extensions/_base"
9
+
10
+ ExtensionsProject.implement(Module, :deep_const_get) do
11
+ class Module
12
+ #
13
+ # Recursively dereferences constants separated by "<tt>::</tt>".
14
+ #
15
+ # _const_ is a Symbol or responds to #to_str, for compatibility with the builtin method
16
+ # <tt>Module#const_get</tt>.
17
+ #
18
+ # Object.const_get("String") # -> String
19
+ # Object.const_get(:String) # -> String
20
+ #
21
+ # Object.deep_const_get("String") # -> String
22
+ # Object.deep_const_get(:String) # -> String
23
+ #
24
+ # Object.deep_const_get("Process::Sys") # -> Process::Sys
25
+ # Object.deep_const_get("Regexp::IGNORECASE") # -> 1
26
+ # Object.deep_const_get("Regexp::MULTILINE") # -> 4
27
+ #
28
+ # require 'test/unit'
29
+ # Test.deep_const_get("Unit::Assertions") # -> Test::Unit::Assertions
30
+ # Test.deep_const_get("::Test::Unit") # -> Test::Unit
31
+ #
32
+ # For resolving classes or modules based on their name, see Module.by_name, which uses this
33
+ # method.
34
+ #
35
+ def deep_const_get(const)
36
+ if Symbol === const
37
+ const = const.to_s
38
+ else
39
+ const = const.to_str.dup
40
+ end
41
+ if const.sub!(/^::/, '')
42
+ base = Object
43
+ else
44
+ base = self
45
+ end
46
+ const.split(/::/).inject(base) { |mod, name| mod.const_get(name) }
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+ ExtensionsProject.implement(Module, :by_name, :class) do
53
+ class Module
54
+ #
55
+ # <em>Note: the following documentation uses "class" because it's more common, but it
56
+ # applies to modules as well.</em>
57
+ #
58
+ # Given the _name_ of a class, returns the class itself (i.e. instance of Class). The
59
+ # dereferencing starts at Object. That is,
60
+ #
61
+ # Class.by_name("String")
62
+ #
63
+ # is equivalent to
64
+ #
65
+ # Object.get_const("String")
66
+ #
67
+ # The parameter _name_ is expected to be a Symbol or String, or at least to respond to
68
+ # <tt>to_str</tt>.
69
+ #
70
+ # An ArgumentError is raised if _name_ does not correspond to an existing class. If _name_
71
+ # is not even a valid class name, the error you'll get is not defined.
72
+ #
73
+ # Examples:
74
+ #
75
+ # Class.by_name("String") # -> String
76
+ # Class.by_name("::String") # -> String
77
+ # Class.by_name("Process::Sys") # -> Process::Sys
78
+ # Class.by_name("GorillaZ") # -> (ArgumentError)
79
+ #
80
+ # Class.by_name("Enumerable") # -> Enumerable
81
+ # Module.by_name("Enumerable") # -> Enumerable
82
+ #
83
+ def Module.by_name(name)
84
+ if Symbol === name
85
+ name = name.to_s
86
+ else
87
+ name = name.to_str
88
+ end
89
+ result = Object.deep_const_get(name)
90
+ if result.is_a? Module
91
+ return result
92
+ else
93
+ raise ArgumentError, "#{name} is not a class or module"
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+
100
+ ExtensionsProject.implement(Module, :basename) do
101
+ class Module
102
+ #
103
+ # Returns the immediate name of the class/module, stripped of any containing classes or
104
+ # modules. Compare Ruby's builtin methods <tt>Module#name</tt> and <tt>File.basename</tt>.
105
+ #
106
+ # Process::Sys.name # -> "Process::Sys"
107
+ # Process::Sys.basename # -> "Sys"
108
+ # String.basename # -> "String"
109
+ #
110
+ def basename
111
+ self.name.sub(/^.*::/, '')
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,230 @@
1
+ #!/usr/local/bin/ruby -w
2
+ #
3
+ # == extensions/integer.rb
4
+ #
5
+ # Adds methods to the builtin Numeric and Integer classes.
6
+ #
7
+
8
+ require "extensions/_base"
9
+
10
+ #
11
+ # * Integer#even?
12
+ #
13
+ ExtensionsProject.implement(Integer, :even?) do
14
+ class Integer
15
+ #
16
+ # Returns true if this integer is even, false otherwise.
17
+ # 14.even? # -> true
18
+ # 15.even? # -> false
19
+ #
20
+ def even?
21
+ self % 2 == 0
22
+ end
23
+ end
24
+ end
25
+
26
+
27
+ #
28
+ # * Integer#odd?
29
+ #
30
+ ExtensionsProject.implement(Integer, :odd?) do
31
+ class Integer
32
+ #
33
+ # Returns true if this integer is odd, false otherwise.
34
+ # -99.odd? # -> true
35
+ # -98.odd? # -> false
36
+ #
37
+ def odd?
38
+ self % 2 == 1
39
+ end
40
+ end
41
+ end
42
+
43
+ #
44
+ # This code arose from discussions with Francis Hwang. Leaving it here for future work.
45
+ #
46
+ # class Numeric
47
+ # def precision_format(nplaces, flag = :pad)
48
+ # format = "%.#{nplaces}f"
49
+ # result = sprintf(format, self)
50
+ # case flag
51
+ # when :pad
52
+ # when :nopad
53
+ # result.sub!(/\.?0*$/, '')
54
+ # else
55
+ # raise ArgumentError, "Invalid value for flag: #{flag.inspect}"
56
+ # end
57
+ # result
58
+ # end
59
+ # end
60
+ #
61
+ # 100.precision_format(2) # -> "100.00"
62
+ # 100.precision_format(2, :nopad) # -> "100"
63
+ # 100.1.precision_format(2) # -> "100.10"
64
+ # 100.1.precision_format(2, :nopad) # -> "100.1"
65
+ # 100.1.precision_format(2, false)
66
+ # # -> "ArgumentError: Invalid value for flag: false"
67
+ #
68
+
69
+
70
+ ExtensionsProject.implement(Numeric, :format_s) do
71
+ #--
72
+ # Copyright � 2003 Austin Ziegler
73
+ #
74
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
75
+ # of this software and associated documentation files (the "Software"), to
76
+ # deal in the Software without restriction, including without limitation the
77
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
78
+ # sell copies of the Software, and to permit persons to whom the Software is
79
+ # furnished to do so, subject to the following conditions:
80
+ #
81
+ # The above copyright notice and this permission notice shall be included in
82
+ # all copies or substantial portions of the Software.
83
+ #
84
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
85
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
86
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
87
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
88
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
89
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
90
+ # IN THE SOFTWARE.
91
+ #++
92
+ class Numeric
93
+ #
94
+ # Provides the base formatting styles for #format_s. See #format_s for
95
+ # more details. Two keys provided that are not supported in the
96
+ # #format_s arguments are:
97
+ #
98
+ # <tt>:style</tt>:: Allows a style to inherit from other styles. Styles
99
+ # will be applied in oldest-first order in the event
100
+ # of multiple inheritance layers.
101
+ # <tt>:id</tt>:: This must be provided on any default style created
102
+ # or provided so as to provide a stop marker so that
103
+ # recursive styles do not result in an infinite loop.
104
+ #
105
+ # This is an implementation detail, not important for users of the class.
106
+ #
107
+ FORMAT_STYLES = {
108
+ :us => { :sep => ',', :dec => '.', :id => :us },
109
+ :usd => { :style => :us, :currency => { :id => "$", :pos => :before }, :id => :usd },
110
+ :eu => { :sep => ' ', :dec => ',', :id => :us },
111
+ :euro => { :style => :eu, :currency => { :id => "�", :pos => :before }, :id => :euro },
112
+ :percent => { :style => :us, :currency => { :id => "%%", :pos => :after }, :id => :percent }
113
+ }
114
+
115
+ #
116
+ # Format a number as a string, using US or European conventions, and
117
+ # allowing for the accounting format of representing negative numbers.
118
+ # Optionally, currency formatting options can be provided.
119
+ #
120
+ # For example:
121
+ # x = -10259.8937
122
+ # x.format_s # => "-10,259.8937"
123
+ # x.format_s(:us) # => "-10,259.8937"
124
+ # x.format_s(:usd) # => "$-10,259.8937"
125
+ # x.format_s(:eu) # => "-10 259,8937"
126
+ # x.format_s(:euro) # => "�-10 259,8937"
127
+ # x.format_s(:us, :acct => true) # => "(10,259.8937)"
128
+ # x.format_s(:eu, :acct => true) # => "(10 259,8937)"
129
+ # x.format_s(:usd, :acct => true) # => "$(10,259.8937)"
130
+ # x.format_s(:euro, :acct => true) # => "�(10 259,8937)"
131
+ # x.format_s(:percent) # => "-10,259.8937%"
132
+ #
133
+ # You may configure several aspects of the formatting by providing keyword
134
+ # arguments after the country and accounting arguments. One example of that
135
+ # is the :acct keyword. A more insane example is:
136
+ #
137
+ # x = -10259.8937
138
+ # x.format_s(:us,
139
+ # :sep => ' ', :dec => ',',
140
+ # :neg => '<%s>', :size => 2,
141
+ # :fd => true) # -> "<1 02 59,89 37>"
142
+ #
143
+ # The keyword parameters are as follows:
144
+ #
145
+ # <tt>:acct</tt>:: If +true+, then use accounting style for negative
146
+ # numbers. This overrides any value for
147
+ # <tt>:neg</tt>.
148
+ # <tt>:sep</tt>:: Default "," for US, " " for Euro. Separate the
149
+ # number groups from each other with this string.
150
+ # <tt>:dec</tt>:: Default "." for US, "," for Euro. Separate the
151
+ # number's integer part from the fractional part
152
+ # with this string.
153
+ # <tt>:neg</tt>:: Default <tt>"-%s"</tt>. The format string used to
154
+ # represent negative numbers. If <tt>:acct</tt> is
155
+ # +true+, this is set to <tt>"(%s)"</tt>.
156
+ # <tt>:size</tt>:: The number of digits per group. Defaults to
157
+ # thousands (3).
158
+ # <tt>:fd</tt>:: Indicates whether the decimal portion of the
159
+ # number should be formatted the same way as the
160
+ # integer portion of the number. ("fd" == "format
161
+ # decimal".) Defaults to +false+.
162
+ # <tt>:currency</tt>:: This is an optional hash with two keys,
163
+ # <tt>:id</tt> and <tt>:pos</tt>. <tt>:id</tt> is
164
+ # the string value of the currency (e.g.,
165
+ # <tt>"$"</tt>, <tt>"�"</tt>, <tt>"USD&nbsp;"</tt>);
166
+ # <tt>:pos</tt> is either <tt>:before</tt> or
167
+ # <tt>:after</tt>, referring to the position of the
168
+ # currency indicator. The default <tt>:pos</tt> is
169
+ # <tt>:before</tt>.
170
+ #
171
+ def format_s(style = :us, configs={})
172
+ style = FORMAT_STYLES[style].dup # Adopt US style by default.
173
+
174
+ # Deal with recursive styles.
175
+ if style[:style]
176
+ styles = []
177
+ s = style
178
+ while s[:style]
179
+ s = FORMAT_STYLES[s[:style]].dup
180
+ styles << s
181
+ break if s[:style] = s[:id]
182
+ end
183
+ styles.reverse_each { |s| style.merge!(s) }
184
+ end
185
+ # Merge the configured style.
186
+ style.merge!(configs)
187
+
188
+ sm = style[:sep] || ','
189
+ dp = style[:dec] || '.'
190
+ if style[:acct]
191
+ fmt = '(%s)'
192
+ else
193
+ fmt = style[:neg] || '-%s'
194
+ end
195
+ sz = style[:size] || 3
196
+ format_decimal = style[:fd]
197
+ ng = (self < 0)
198
+ fmt = "%s" if not ng
199
+
200
+ dec, frac = self.abs.to_s.split(/\./)
201
+
202
+ dec.reverse!
203
+ dec.gsub!(/\d{#{sz}}/) { |m| "#{m}#{sm}" }
204
+ dec.gsub!(/#{sm}$/, '')
205
+ dec.reverse!
206
+
207
+ if format_decimal and not frac.nil?
208
+ frac.gsub!(/\d{#{sz}}/) { |m| "#{m}#{sm}" }
209
+ frac.gsub!(/#{sm}$/, '')
210
+ end
211
+
212
+ if frac.nil?
213
+ val = dec
214
+ else
215
+ val = "#{dec}#{dp}#{frac}"
216
+ end
217
+
218
+ if style[:currency]
219
+ if style[:currency][:pos].nil? or style[:currency][:pos] == :before
220
+ fmt = "#{style[:currency][:id]}#{fmt}"
221
+ elsif style[:currency][:pos] == :after
222
+ fmt = "#{fmt}#{style[:currency][:id]}"
223
+ end
224
+ end
225
+
226
+ fmt % val
227
+ end
228
+ end # class Numeric
229
+ end # ExtensionsProject.implement
230
+