crosscase 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []