crosscase 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (8) hide show
  1. data/MANIFEST +6 -0
  2. data/README +64 -0
  3. data/crosscase.gemspec +21 -0
  4. data/crosscase.rb +297 -0
  5. data/install.rb +85 -0
  6. data/test.rb +67 -0
  7. data/utils.rb +400 -0
  8. metadata +46 -0
@@ -0,0 +1,6 @@
1
+ crosscase.rb
2
+ install.rb
3
+ test.rb
4
+ utils.rb
5
+ MANIFEST
6
+ README
data/README ADDED
@@ -0,0 +1,64 @@
1
+
2
+ = CrossCase
3
+
4
+ A mixin for auto-generating under_barred aliases for camelCased methods, and
5
+ vice-versa.
6
+
7
+ See crosscase.rb for more details.
8
+
9
+
10
+ == Authors
11
+
12
+ * Michael Granger <ged@FaerieMUD.org>
13
+
14
+ === Thanks
15
+
16
+ * The denizens of #ruby-lang on irc.freenode.net, especially dblack, oGMo, and
17
+ rubyhacker1 who all helped with name suggestions.
18
+
19
+
20
+ == Requirements
21
+
22
+ * Ruby >= 1.8.0
23
+
24
+
25
+ == Installation
26
+
27
+ $ su
28
+ # ruby install.rb
29
+
30
+
31
+ === Documentation
32
+
33
+ If you have Dave Thomas's RDoc system installed, you can generate your very own
34
+ HTML documentation for this module like so:
35
+
36
+ $ rdoc crosscase.rb README
37
+
38
+
39
+ == More Information
40
+
41
+ You can find more information about this module, including any updates, at its
42
+ project page:
43
+
44
+ http://www.deveiate.org/code/CrossCase.shtml
45
+
46
+
47
+ == Legal
48
+
49
+ Copyright � 2003 The FaerieMUD Consortium. All rights reserved.
50
+
51
+ This module is free software. You may use, modify, and/or redistribute this
52
+ software under the same terms as Ruby.
53
+
54
+ THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
55
+ INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
56
+ FITNESS FOR A PARTICULAR PURPOSE.
57
+
58
+
59
+ $Id: README,v 1.1 2003/07/25 16:54:09 deveiant Exp $
60
+
61
+
62
+
63
+
64
+
@@ -0,0 +1,21 @@
1
+ require 'date'
2
+ Gem::Specification.new do |s|
3
+ s.name = %q{crosscase}
4
+ s.version = "0.0.1"
5
+ s.date = Date.today.to_s
6
+ s.summary = %q{A mixin for auto-generating under_barred aliases for camelCased methods, and vice-versa.}
7
+ s.description =<<DESCRIPTION
8
+ A mixin for auto-generating under_barred aliases for camelCased methods, and vice-versa.
9
+ DESCRIPTION
10
+ s.author = %q{Michael Granger}
11
+ s.email = %q{ged@FaerieMUD.org}
12
+ s.homepage = %q{http://www.deveiate.org/code/CrossCase.html}
13
+ s.files = Dir.glob('**/*')
14
+ s.require_path = %q{.}
15
+ s.autorequire = %q{crosscase}
16
+ s.has_rdoc = true
17
+ s.rdoc_options = ["--main", "README"]
18
+ s.extra_rdoc_files = ["README"]
19
+ s.test_files = %w{test.rb}
20
+ s.required_ruby_version = Gem::Version::Requirement.new(">= 1.8.0")
21
+ end
@@ -0,0 +1,297 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # CrossCase - a mixin for making methods look the way you like 'em. Or for
4
+ # making them look the way other people like 'em. Or something.
5
+ #
6
+ # == Synopsis
7
+ #
8
+ # class MyClass
9
+ # include CrossCase
10
+ #
11
+ # def underbarred_method; ...; end
12
+ # def camelCasedMethod; ...; end
13
+ # end
14
+ #
15
+ # obj = MyClass::new
16
+ # obj.underbarredMethod
17
+ # obj.camel_cased_method
18
+ #
19
+ # # -or-
20
+ #
21
+ # class MyClass
22
+ # def underbarred_method; ...; end
23
+ # def camelCasedMethod; ...; end
24
+ # end
25
+ #
26
+ # MyClass.extend( CrossCase )
27
+ # obj = MyClass::new
28
+ # obj.underbarredMethod
29
+ # obj.camel_cased_method
30
+ #
31
+ # == Description
32
+ #
33
+ # This module, when mixed into a Class or another Module, will provide
34
+ # under_barred aliases for class or instance methods with names which follow the
35
+ # camelCased naming conventions, and vice-versa. E.g., in a class which mixes in
36
+ # CrossCase, defining a method which is called +foo_bar+ will also create an
37
+ # alias for that method called +fooBar+.
38
+ #
39
+ # I wrote this module because I prefer camelCased method names, but also wish to
40
+ # respect the preferences of my fellow Rubyists for whom such practices are an
41
+ # abomination. And I'm too lazy to type
42
+ # alias :twinkle_twinkle :twinkleTwinkle
43
+ # for every method. It's all about laziness. Or perhaps I'm catering to my
44
+ # hubris. Or both; I'll shut up now.
45
+ #
46
+ # == Caveats
47
+ #
48
+ # This module uses the +method_added+ and +singleton_method_added+ hooks to
49
+ # generate aliases for new methods. If either or both of these methods are
50
+ # already defined, they will be preserved as aliases when the Class or Module is
51
+ # extended. It's up to you to return the favor should you create your own hook
52
+ # after this module is mixed in to your class.
53
+ #
54
+ # == Authors
55
+ #
56
+ # * Michael Granger <ged@FaerieMUD.org>
57
+ #
58
+ # === Thanks To
59
+ #
60
+ # * The denizens of irc://irc.freenode.net/#ruby-lang, and especially dblack,
61
+ # oGMo, and rubyhacker1 for name suggestions.
62
+ #
63
+ # == Copyright
64
+ #
65
+ # Copyright (c) 2003 The FaerieMUD Consortium. All rights reserved.
66
+ #
67
+ # This module is free software. You may use, modify, and/or redistribute this
68
+ # software under the same terms as Ruby
69
+ #
70
+ # This program is distributed in the hope that it will be useful, but WITHOUT
71
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
72
+ # FOR A PARTICULAR PURPOSE.
73
+ #
74
+ # == Version
75
+ #
76
+ # $Id: crosscase.rb,v 1.2 2003/07/25 17:00:24 deveiant Exp $
77
+ #
78
+
79
+
80
+ ### A mixin which causes aliases for methods with either under_barred or
81
+ ### camelCased naming conventions to be created in the opposing
82
+ ### convention. E.g., in a class which mixes in CrossCase, defining a method
83
+ ### which is called +foo_bar+ will also create an alias for that method called
84
+ ### +fooBar+.
85
+ module CrossCase
86
+
87
+ ### Versioning constants
88
+ Version = /([\d\.]+)/.match( %q{$Revision: 1.2 $} )[1]
89
+ Rcsid = %q$Id: crosscase.rb,v 1.2 2003/07/25 17:00:24 deveiant Exp $
90
+
91
+ ### The inclusion callback -- uses the Ouroboros trick to extend including
92
+ ### classes.
93
+ def self::included( mod )
94
+ mod.extend( self )
95
+ end
96
+
97
+
98
+ ### Object-extension callback -- installs aliases for any currently-extant
99
+ ### class or instance methods, and installs callbacks that will create
100
+ ### aliases for any subsequently-defined methods. Raises an error if any
101
+ ### object except a Class or Module is extended.
102
+ def self::extend_object( mod )
103
+ raise TypeError, "Expected a Module or a Class, got a " +
104
+ mod.class.name unless
105
+ mod.is_a?( Module )
106
+
107
+ self::transformClassMethods( mod )
108
+ self::transformInstanceMethods( mod )
109
+ self::installMethodHooks( mod )
110
+ end
111
+
112
+
113
+ ### Install +method_added+ and +singleton_method_added+ hooks into the given
114
+ ### Module +mod+ which auto-generate aliases for new methods.
115
+ def self::installMethodHooks( mod )
116
+ mod.module_eval {
117
+ class << self
118
+ if respond_to?( :singleton_method_added )
119
+ alias :__cc_sma :singleton_method_added
120
+ end
121
+ def singleton_method_added( id )
122
+ if aliasName = CrossCase::transform( id )
123
+ CrossCase::installClassAlias( self, id, aliasName )
124
+ end
125
+ if respond_to?( :__cc_sma )
126
+ __cc_sma( id )
127
+ else
128
+ super
129
+ end
130
+ end
131
+
132
+ if respond_to?( :method_added )
133
+ alias :__cc_ma :method_added
134
+ end
135
+ def method_added( id )
136
+ if aliasName = CrossCase::transform( id )
137
+ CrossCase::installAlias( self, id, aliasName )
138
+ end
139
+ if respond_to?( :__cc_ma )
140
+ __cc_ma( id )
141
+ else
142
+ super
143
+ end
144
+ end
145
+ end
146
+ }
147
+ end
148
+
149
+
150
+ ### Search for and install aliases for either underbarred or camelCased
151
+ ### class methods for +mod+ (a Class or Module).
152
+ def self::transformClassMethods( mod )
153
+ self::findTargetMethods( mod.singleton_methods(false) ) {|meth, aliasName|
154
+ self::installClassAlias( mod, meth, aliasName )
155
+ }
156
+ end
157
+
158
+
159
+ ### Install an alias +aliasName+ for the given class method +meth+ of the
160
+ ### Class or Module +mod+.
161
+ def self::installClassAlias( mod, meth, aliasName )
162
+ unless mod.respond_to?( aliasName )
163
+ code = %{
164
+ class << self; alias_method( :#{aliasName}, :#{meth} ); end
165
+ }
166
+ mod.module_eval( code, __FILE__, __LINE__ )
167
+ end
168
+ end
169
+
170
+
171
+ ### Search for and install aliases for either underbarred or camelCased
172
+ ### instance methods for +mod+ (a Class or Module).
173
+ def self::transformInstanceMethods( mod )
174
+ self::findTargetMethods( mod.instance_methods(false) ) {|meth, aliasName|
175
+ self::installAlias( mod, meth, aliasName )
176
+ }
177
+ end
178
+
179
+
180
+ ### Install an alias +aliasName+ for the given instance method +meth+ of the
181
+ ### Class or Module +mod+.
182
+ def self::installAlias( mod, meth, aliasName )
183
+ unless mod.instance_methods(true).include?( aliasName )
184
+ mod.module_eval %{alias_method :#{aliasName}, :#{meth}}
185
+ end
186
+ end
187
+
188
+
189
+ ### Find methods in the given +methodList+ which are candidates for
190
+ ### aliasing.
191
+ def self::findTargetMethods( *methodList )
192
+ methodList.flatten.each {|meth|
193
+ next if /(singleton_)?method_added/ =~ meth
194
+ transformedName = transform( meth ) or next
195
+ yield( meth, transformedName )
196
+ }
197
+ end
198
+
199
+
200
+ ### Return an alternate name for the given method id +mid+. If the method id
201
+ ### is an under_barred method, returns a camelCased version, and
202
+ ### vice-versa. If no alternate is called for, returns +nil+.
203
+ def self::transform( mid )
204
+ methodName = mid.to_s
205
+ transformedName = ''
206
+
207
+ # camelCased methods
208
+ if /[A-Z]/.match( methodName ) && !/_/.match( methodName )
209
+ transformedName = methodName.gsub( /([a-z0-9])([A-Z])/ ) {|match|
210
+ $1 + '_' + $2
211
+ }.downcase
212
+
213
+ # underbarred_methods
214
+ elsif !/A-Z/.match( methodName ) && /[a-z0-9]_[a-z]/.match( methodName )
215
+ transformedName = methodName.gsub( /([a-z0-9])_([a-z])/ ) {|match|
216
+ $1 + $2.upcase
217
+ }
218
+
219
+ else
220
+ transformedName = nil
221
+ end
222
+
223
+ return transformedName
224
+ end
225
+
226
+
227
+ end
228
+
229
+
230
+ if $0 == __FILE__
231
+ require './utils'
232
+ include UtilityFunctions
233
+ $yaml = false
234
+
235
+ class Foo #:nodoc:
236
+ def self::singleton_method_added( id )
237
+ $stderr.puts "Original sma: Added #{id} to #{self.inspect}"
238
+ end
239
+
240
+ def self::method_added( id )
241
+ $stderr.puts "Original ma: Added #{id} to #{self.inspect}"
242
+ end
243
+
244
+ def self::classPreCamelMethod
245
+ "classPreCamelMethod"
246
+ end
247
+
248
+ def self::class_pre_underbarred_method
249
+ "class_pre_underbarred_method"
250
+ end
251
+
252
+ def preCamelCasedMethod
253
+ "preCamelCasedMethod"
254
+ end
255
+
256
+ def pre_underbarred_method
257
+ "pre_underbarred_method"
258
+ end
259
+
260
+ extend CrossCase
261
+
262
+ def self::classCamelMethod
263
+ "classCamelMethod"
264
+ end
265
+
266
+ def self::class_underbarred_method
267
+ "class_underbarred_method"
268
+ end
269
+
270
+ def camelCasedMethod
271
+ "camelCasedMethod"
272
+ end
273
+
274
+ def underbarred_method
275
+ "underbarred_method"
276
+ end
277
+ end
278
+
279
+ f = nil
280
+ try( "to instantiate Foo" ) { f = Foo::new }
281
+ %w{classPreCamelMethod class_pre_camel_method
282
+ class_pre_underbarred_method classPreUnderbarredMethod
283
+ classCamelMethod class_camel_method
284
+ class_underbarred_method classUnderbarredMethod
285
+ }.
286
+ sort.each {|meth|
287
+ try( "to call #{meth} on Foo" ) {
288
+ Foo.send( meth )
289
+ }
290
+ }
291
+ Foo.instance_methods(false).sort.each {|meth|
292
+ try( "to call #{meth} on the instance of Foo" ) {
293
+ f.send( meth )
294
+ }
295
+ }
296
+ end
297
+
@@ -0,0 +1,85 @@
1
+ # install.rb
2
+ #
3
+ # $Date: 2003/07/25 15:43:29 $
4
+ # Copyright (c) 2000 Masatoshi SEKI
5
+ #
6
+ # install.rb is copyrighted free software by Masatoshi SEKI.
7
+ # You can redistribute it and/or modify it under the same term as Ruby.
8
+
9
+ require 'rbconfig'
10
+ require 'find'
11
+ require 'ftools'
12
+
13
+ include Config
14
+
15
+ class Installer
16
+ protected
17
+ def install(from, to, mode = nil, verbose = false)
18
+ str = "install '#{from}' to '#{to}'"
19
+ str += ", mode=#{mode}" if mode
20
+ puts str if verbose
21
+ end
22
+
23
+ protected
24
+ def makedirs(*dirs)
25
+ for d in dirs
26
+ puts "mkdir #{d}"
27
+ end
28
+ end
29
+
30
+ def initialize(test=false)
31
+ @version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
32
+ @libdir = File.join(CONFIG["libdir"], "ruby", @version)
33
+ @sitelib = find_site_libdir
34
+ @ftools = (test) ? self : File
35
+ end
36
+ public
37
+ attr_reader(:libdir, :sitelib)
38
+
39
+ private
40
+ def find_site_libdir
41
+ site_libdir = $:.find {|x| x =~ /site_ruby$/}
42
+ if !site_libdir
43
+ site_libdir = File.join(@libdir, "site_ruby")
44
+ elsif site_libdir !~ Regexp::new( Regexp.quote(@version) )
45
+ site_libdir = File.join(site_libdir, @version)
46
+ end
47
+ site_libdir
48
+ end
49
+
50
+ public
51
+ def files_in_dir(dir)
52
+ list = []
53
+ Find.find(dir) do |f|
54
+ list.push(f)
55
+ end
56
+ list
57
+ end
58
+
59
+ public
60
+ def install_files(srcdir, files, destdir=@sitelib)
61
+ path = []
62
+ dir = []
63
+
64
+ for f in files
65
+ next if (f = f[srcdir.length+1..-1]) == nil
66
+ path.push f if File.ftype(File.join(srcdir, f)) == 'file'
67
+ dir |= [ File.dirname(File.join(destdir, f)) ]
68
+ end
69
+ @ftools.makedirs(*dir)
70
+ for f in path
71
+ @ftools.install(File.join(srcdir, f), File.join(destdir, f), nil, true)
72
+ end
73
+ end
74
+
75
+ public
76
+ def install_rb
77
+ intall_files('lib', files_in_dir('lib'))
78
+ end
79
+ end
80
+
81
+ if __FILE__ == $0
82
+ inst = Installer.new(ARGV.shift == '-n')
83
+ inst.install_files('.', ['./crosscase.rb'])
84
+ end
85
+
data/test.rb ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/ruby
2
+ # = test.rb
3
+ #
4
+ # Test suite for CrossCase
5
+ #
6
+ # == Author
7
+ #
8
+ # Michael Granger <ged@FaerieMUD.org>
9
+ #
10
+ # Copyright (c) 2003 The FaerieMUD Consortium. All rights reserved.
11
+ #
12
+ # This program is free software. You may use, modify, and/or redistribute this
13
+ # software under the same terms as Ruby itself.
14
+ #
15
+ # This program is distributed in the hope that it will be useful, but WITHOUT
16
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
+ # FOR A PARTICULAR PURPOSE.
18
+ #
19
+ # == Version
20
+ #
21
+ # $Id: test.rb,v 1.1.1.1 2003/07/25 15:43:29 deveiant Exp $
22
+ #
23
+ #
24
+
25
+ $:.unshift "."
26
+
27
+ require 'test/unit'
28
+ require 'crosscase'
29
+
30
+ $stderr.sync = $stdout.sync = true
31
+
32
+ ### Reactor test case
33
+ class CrossCaseTestCase < Test::Unit::TestCase
34
+
35
+ # Test to be sure the module loaded
36
+ def test_00_module
37
+ assert_instance_of Module, CrossCase, "CrossCase module didn't load"
38
+ end
39
+
40
+ # Test pre-include
41
+ def test_10_preinclude
42
+ rval = obj = testClass = nil
43
+
44
+ assert_nothing_raised {
45
+ testClass = Class::new( Object ) {
46
+ include CrossCase
47
+ def underbarred_method; "under_barred"; end
48
+ def camelCasedMethod; "camelCased"; end
49
+ }
50
+ }
51
+
52
+ obj = testClass::new
53
+ assert_respond_to obj, :underbarredMethod,
54
+ "alias for underbarred_method"
55
+ assert_respond_to obj, :camel_cased_method,
56
+ "alias for camelCasedMethod"
57
+ end
58
+
59
+ end # class CrossCaseTestCase
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
@@ -0,0 +1,400 @@
1
+ #
2
+ # Install/distribution utility functions
3
+ # $Id: utils.rb,v 1.1.1.1 2003/07/25 15:43:29 deveiant Exp $
4
+ #
5
+ # Copyright (c) 2001-2003, The FaerieMUD Consortium.
6
+ #
7
+ # This is free software. You may use, modify, and/or redistribute this
8
+ # software under the terms of the Perl Artistic License. (See
9
+ # http://language.perl.com/misc/Artistic.html)
10
+ #
11
+
12
+
13
+ BEGIN {
14
+ begin
15
+ require 'readline'
16
+ include Readline
17
+ rescue LoadError => e
18
+ $stderr.puts "Faking readline..."
19
+ def readline( prompt )
20
+ $stderr.print prompt.chomp
21
+ return $stdin.gets.chomp
22
+ end
23
+ end
24
+
25
+ begin
26
+ require 'yaml'
27
+ $yaml = true
28
+ rescue LoadError => e
29
+ $stderr.puts "No YAML; try() will use .inspect instead."
30
+ $yaml = false
31
+ end
32
+ }
33
+
34
+ module UtilityFunctions
35
+
36
+ # The list of regexen that eliminate files from the MANIFEST
37
+ ANTIMANIFEST = [
38
+ /makedist\.rb/,
39
+ /\bCVS\b/,
40
+ /~$/,
41
+ /^#/,
42
+ %r{docs/html},
43
+ %r{docs/man},
44
+ /^TEMPLATE/,
45
+ /\.cvsignore/,
46
+ /\.s?o$/
47
+ ]
48
+
49
+ # Set some ANSI escape code constants (Shamelessly stolen from Perl's
50
+ # Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
51
+ AnsiAttributes = {
52
+ 'clear' => 0,
53
+ 'reset' => 0,
54
+ 'bold' => 1,
55
+ 'dark' => 2,
56
+ 'underline' => 4,
57
+ 'underscore' => 4,
58
+ 'blink' => 5,
59
+ 'reverse' => 7,
60
+ 'concealed' => 8,
61
+
62
+ 'black' => 30, 'on_black' => 40,
63
+ 'red' => 31, 'on_red' => 41,
64
+ 'green' => 32, 'on_green' => 42,
65
+ 'yellow' => 33, 'on_yellow' => 43,
66
+ 'blue' => 34, 'on_blue' => 44,
67
+ 'magenta' => 35, 'on_magenta' => 45,
68
+ 'cyan' => 36, 'on_cyan' => 46,
69
+ 'white' => 37, 'on_white' => 47
70
+ }
71
+
72
+ ErasePreviousLine = "\033[A\033[K"
73
+
74
+
75
+ ###############
76
+ module_function
77
+ ###############
78
+
79
+ # Create a string that contains the ANSI codes specified and return it
80
+ def ansiCode( *attributes )
81
+ return '' unless /(?:vt10[03]|xterm(?:-color)?|linux)/i =~ ENV['TERM']
82
+ attr = attributes.collect {|a| AnsiAttributes[a] ? AnsiAttributes[a] : nil}.compact.join(';')
83
+ if attr.empty?
84
+ return ''
85
+ else
86
+ return "\e[%sm" % attr
87
+ end
88
+ end
89
+
90
+ # Test for the presence of the specified <tt>library</tt>, and output a
91
+ # message describing the test using <tt>nicename</tt>. If <tt>nicename</tt>
92
+ # is <tt>nil</tt>, the value in <tt>library</tt> is used to build a default.
93
+ def testForLibrary( library, nicename=nil )
94
+ nicename ||= library
95
+ message( "Testing for the #{nicename} library..." )
96
+ if $:.detect {|dir| File.exists?(File.join(dir,"#{library}.rb")) || File.exists?(File.join(dir,"#{library}.so"))}
97
+ message( "found.\n" )
98
+ return true
99
+ else
100
+ message( "not found.\n" )
101
+ return false
102
+ end
103
+ end
104
+
105
+ # Test for the presence of the specified <tt>library</tt>, and output a
106
+ # message describing the problem using <tt>nicename</tt>. If
107
+ # <tt>nicename</tt> is <tt>nil</tt>, the value in <tt>library</tt> is used
108
+ # to build a default. If <tt>raaUrl</tt> and/or <tt>downloadUrl</tt> are
109
+ # specified, they are also use to build a message describing how to find the
110
+ # required library. If <tt>fatal</tt> is <tt>true</tt>, a missing library
111
+ # will cause the program to abort.
112
+ def testForRequiredLibrary( library, nicename=nil, raaUrl=nil, downloadUrl=nil, fatal=true )
113
+ nicename ||= library
114
+ unless testForLibrary( library, nicename )
115
+ msgs = [ "You are missing the required #{nicename} library.\n" ]
116
+ msgs << "RAA: #{raaUrl}\n" if raaUrl
117
+ msgs << "Download: #{downloadUrl}\n" if downloadUrl
118
+ if fatal
119
+ abort msgs.join('')
120
+ else
121
+ errorMessage msgs.join('')
122
+ end
123
+ end
124
+ return true
125
+ end
126
+
127
+ ### Output <tt>msg</tt> as a ANSI-colored program/section header (white on
128
+ ### blue).
129
+ def header( msg )
130
+ msg.chomp!
131
+ $stderr.puts ansiCode( 'bold', 'white', 'on_blue' ) + msg + ansiCode( 'reset' )
132
+ $stderr.flush
133
+ end
134
+
135
+ ### Output <tt>msg</tt> to STDERR and flush it.
136
+ def message( msg )
137
+ $stderr.print ansiCode( 'cyan' ) + msg + ansiCode( 'reset' )
138
+ $stderr.flush
139
+ end
140
+
141
+ ### Output the specified <tt>msg</tt> as an ANSI-colored error message
142
+ ### (white on red).
143
+ def errorMessage( msg )
144
+ message ansiCode( 'bold', 'white', 'on_red' ) + msg + ansiCode( 'reset' )
145
+ end
146
+
147
+ ### Output the specified <tt>msg</tt> as an ANSI-colored debugging message
148
+ ### (yellow on blue).
149
+ def debugMsg( msg )
150
+ return unless $DEBUG
151
+ msg.chomp!
152
+ $stderr.puts ansiCode( 'bold', 'yellow', 'on_blue' ) + ">>> #{msg}" + ansiCode( 'reset' )
153
+ $stderr.flush
154
+ end
155
+
156
+ ### Erase the previous line (if supported by your terminal) and output the
157
+ ### specified <tt>msg</tt> instead.
158
+ def replaceMessage( msg )
159
+ print ErasePreviousLine
160
+ message( msg )
161
+ end
162
+
163
+ ### Output a divider made up of <tt>length</tt> hyphen characters.
164
+ def divider( length=75 )
165
+ puts "\r" + ("-" * length )
166
+ end
167
+ alias :writeLine :divider
168
+
169
+ ### Output the specified <tt>msg</tt> colored in ANSI red and exit with a
170
+ ### status of 1.
171
+ def abort( msg )
172
+ print ansiCode( 'bold', 'red' ) + "Aborted: " + msg.chomp + ansiCode( 'reset' ) + "\n\n"
173
+ Kernel.exit!( 1 )
174
+ end
175
+
176
+ ### Output the specified <tt>promptString</tt> as a prompt (in green) and
177
+ ### return the user's input with leading and trailing spaces removed.
178
+ def prompt( promptString )
179
+ promptString.chomp!
180
+ return readline( ansiCode('bold', 'green') + "#{promptString}: " + ansiCode('reset') ).strip
181
+ end
182
+
183
+ ### Prompt the user with the given <tt>promptString</tt> via #prompt,
184
+ ### substituting the given <tt>default</tt> if the user doesn't input
185
+ ### anything.
186
+ def promptWithDefault( promptString, default )
187
+ response = prompt( "%s [%s]" % [ promptString, default ] )
188
+ if response.empty?
189
+ return default
190
+ else
191
+ return response
192
+ end
193
+ end
194
+
195
+ ### Search for the program specified by the given <tt>progname</tt> in the
196
+ ### user's <tt>PATH</tt>, and return the full path to it, or <tt>nil</tt> if
197
+ ### no such program is in the path.
198
+ def findProgram( progname )
199
+ ENV['PATH'].split(File::PATH_SEPARATOR).each {|d|
200
+ file = File.join( d, progname )
201
+ return file if File.executable?( file )
202
+ }
203
+ return nil
204
+ end
205
+
206
+ ### Using the CVS log for the given <tt>file</tt> attempt to guess what the
207
+ ### next release version might be. This only works if releases are tagged
208
+ ### with tags like 'RELEASE_x_y'.
209
+ def extractNextVersionFromTags( file )
210
+ message "Attempting to extract next release version from CVS tags for #{file}...\n"
211
+ raise RuntimeError, "No such file '#{file}'" unless File.exists?( file )
212
+ cvsPath = findProgram( 'cvs' ) or
213
+ raise RuntimeError, "Cannot find the 'cvs' program. Aborting."
214
+
215
+ output = %x{#{cvsPath} log #{file}}
216
+ release = [ 0, 0 ]
217
+ output.scan( /RELEASE_(\d+)_(\d+)/ ) {|match|
218
+ if $1.to_i > release[0] || $2.to_i > release[1]
219
+ release = [ $1.to_i, $2.to_i ]
220
+ replaceMessage( "Found %d.%02d...\n" % release )
221
+ end
222
+ }
223
+
224
+ if release[1] >= 99
225
+ release[0] += 1
226
+ release[1] = 1
227
+ else
228
+ release[1] += 1
229
+ end
230
+
231
+ return "%d.%02d" % release
232
+ end
233
+
234
+ ### Extract the project name (CVS Repository name) for the given directory.
235
+ def extractProjectName
236
+ File.open( "CVS/Repository", "r").readline.chomp
237
+ end
238
+
239
+ ### Read the specified <tt>manifestFile</tt>, which is a text file
240
+ ### describing which files to package up for a distribution. The manifest
241
+ ### should consist of one or more lines, each containing one filename or
242
+ ### shell glob pattern.
243
+ def readManifest( manifestFile="MANIFEST" )
244
+ message "Building manifest..."
245
+ raise "Missing #{manifestFile}, please remake it" unless File.exists? manifestFile
246
+
247
+ manifest = IO::readlines( manifestFile ).collect {|line|
248
+ line.chomp
249
+ }.select {|line|
250
+ line !~ /^(\s*(#.*)?)?$/
251
+ }
252
+
253
+ filelist = []
254
+ for pat in manifest
255
+ $stderr.puts "Adding files that match '#{pat}' to the file list" if $VERBOSE
256
+ filelist |= Dir.glob( pat ).find_all {|f| FileTest.file?(f)}
257
+ end
258
+
259
+ message "found #{filelist.length} files.\n"
260
+ return filelist
261
+ end
262
+
263
+ ### Given a <tt>filelist</tt> like that returned by #readManifest, remove
264
+ ### the entries therein which match the Regexp objects in the given
265
+ ### <tt>antimanifest</tt> and return the resultant Array.
266
+ def vetManifest( filelist, antimanifest=ANITMANIFEST )
267
+ origLength = filelist.length
268
+ message "Vetting manifest..."
269
+
270
+ for regex in antimanifest
271
+ if $VERBOSE
272
+ message "\n\tPattern /#{regex.source}/ removed: " +
273
+ filelist.find_all {|file| regex.match(file)}.join(', ')
274
+ end
275
+ filelist.delete_if {|file| regex.match(file)}
276
+ end
277
+
278
+ message "removed #{origLength - filelist.length} files from the list.\n"
279
+ return filelist
280
+ end
281
+
282
+ ### Combine a call to #readManifest with one to #vetManifest.
283
+ def getVettedManifest( manifestFile="MANIFEST", antimanifest=ANTIMANIFEST )
284
+ vetManifest( readManifest(manifestFile), antimanifest )
285
+ end
286
+
287
+ ### Given a documentation <tt>catalogFile</tt>, which is in the same format
288
+ ### as that described by #readManifest, read and expand it, and then return
289
+ ### a list of those files which appear to have RDoc documentation in
290
+ ### them. If <tt>catalogFile</tt> is nil or does not exist, the MANIFEST
291
+ ### file is used instead.
292
+ def findRdocableFiles( catalogFile="docs/CATALOG" )
293
+ startlist = []
294
+ if File.exists? catalogFile
295
+ message "Using CATALOG file (%s).\n" % catalogFile
296
+ startlist = getVettedManifest( catalogFile )
297
+ else
298
+ message "Using default MANIFEST\n"
299
+ startlist = getVettedManifest()
300
+ end
301
+
302
+ message "Looking for RDoc comments in:\n" if $VERBOSE
303
+ startlist.select {|fn|
304
+ message " #{fn}: " if $VERBOSE
305
+ found = false
306
+ File::open( fn, "r" ) {|fh|
307
+ fh.each {|line|
308
+ if line =~ /^(\s*#)?\s*=/ || line =~ /:\w+:/ || line =~ %r{/\*}
309
+ found = true
310
+ break
311
+ end
312
+ }
313
+ }
314
+
315
+ message( (found ? "yes" : "no") + "\n" ) if $VERBOSE
316
+ found
317
+ }
318
+ end
319
+
320
+ ### Open a file and filter each of its lines through the given block a
321
+ ### <tt>line</tt> at a time. The return value of the block is used as the
322
+ ### new line, or omitted if the block returns <tt>nil</tt> or
323
+ ### <tt>false</tt>.
324
+ def editInPlace( file ) # :yields: line
325
+ raise "No block specified for editing operation" unless block_given?
326
+
327
+ tempName = "#{file}.#{$$}"
328
+ File::open( tempName, File::RDWR|File::CREAT, 0600 ) {|tempfile|
329
+ File::unlink( tempName )
330
+ File::open( file, File::RDONLY ) {|fh|
331
+ fh.each {|line|
332
+ newline = yield( line ) or next
333
+ tempfile.print( newline )
334
+ }
335
+ }
336
+
337
+ tempfile.seek(0)
338
+
339
+ File::open( file, File::TRUNC|File::WRONLY, 0644 ) {|newfile|
340
+ newfile.print( tempfile.read )
341
+ }
342
+ }
343
+ end
344
+
345
+ ### Execute the specified shell <tt>command</tt>, read the results, and
346
+ ### return them. Like a %x{} that returns an Array instead of a String.
347
+ def shellCommand( *command )
348
+ raise "Empty command" if command.empty?
349
+
350
+ cmdpipe = IO::popen( command.join(' '), 'r' )
351
+ return cmdpipe.readlines
352
+ end
353
+
354
+ ### Execute a block with $VERBOSE set to +false+, restoring it to its
355
+ ### previous value before returning.
356
+ def verboseOff
357
+ raise LocalJumpError, "No block given" unless block_given?
358
+
359
+ thrcrit = Thread.critical
360
+ oldverbose = $VERBOSE
361
+ begin
362
+ Thread.critical = true
363
+ $VERBOSE = false
364
+ yield
365
+ ensure
366
+ $VERBOSE = oldverbose
367
+ Thread.critical = false
368
+ end
369
+ end
370
+
371
+
372
+ ### Try the specified code block, printing the given
373
+ def try( msg, bind=nil )
374
+ result = nil
375
+ message "Trying #{msg}..."
376
+
377
+ begin
378
+ rval = nil
379
+ if block_given?
380
+ rval = yield
381
+ else
382
+ file, line = caller(1)[0].split(/:/,2)
383
+ rval = eval( msg, bind, file, line.to_i )
384
+ end
385
+
386
+ if $yaml
387
+ result = rval.to_yaml
388
+ else
389
+ result = rval.inspect
390
+ end
391
+ rescue Exception => err
392
+ nicetrace = err.backtrace.delete_if {|frame|
393
+ /in `(try|eval)'/ =~ frame
394
+ }.join("\n\t")
395
+ result = err.message + "\n\t" + nicetrace
396
+ ensure
397
+ puts result
398
+ end
399
+ end
400
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: "0.8"
3
+ specification_version: 1
4
+ name: crosscase
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2004-10-27
8
+ summary: "A mixin for auto-generating under_barred aliases for camelCased methods, and vice-versa."
9
+ require_paths:
10
+ - "."
11
+ author: Michael Granger
12
+ email: ged@FaerieMUD.org
13
+ homepage: http://www.deveiate.org/code/CrossCase.html
14
+ rubyforge_project:
15
+ description: "A mixin for auto-generating under_barred aliases for camelCased methods, and vice-versa."
16
+ autorequire: crosscase
17
+ default_executable:
18
+ bindir: bin
19
+ has_rdoc: true
20
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
21
+ requirements:
22
+ -
23
+ - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 1.8.0
26
+ version:
27
+ platform: ruby
28
+ files:
29
+ - README
30
+ - crosscase.rb
31
+ - install.rb
32
+ - test.rb
33
+ - MANIFEST
34
+ - utils.rb
35
+ - crosscase.gemspec
36
+ test_files:
37
+ - test.rb
38
+ rdoc_options:
39
+ - "--main"
40
+ - README
41
+ extra_rdoc_files:
42
+ - README
43
+ executables: []
44
+ extensions: []
45
+ requirements: []
46
+ dependencies: []