Module: CrossCase

Included in:
Foo
Defined in:
lib/mega/crosscase.rb

Overview

:title: CrossCase

CrossCase - a mixin for making methods look the way you like ‘em. Or for making them look the way other people like ’em. Or something. Let’s try that again… CrossCase - A mixin for auto-generating under_barred aliases for camelCased methods, and vice-versa. Better.

Synopsis

class MyClass
  include CrossCase

  def underbarred_method; ...; end
  def camelCasedMethod; ...; end
end

obj = MyClass::new
obj.underbarredMethod
obj.camel_cased_method

-or-

class MyClass
  def underbarred_method; ...; end
  def camelCasedMethod; ...; end
end

MyClass.extend( CrossCase )
obj = MyClass::new
obj.underbarredMethod
obj.camel_cased_method

Details

This module, when mixed into a Class or another Module, will provide under_barred aliases for class or instance methods with names which follow the camelCased naming conventions, and vice-versa. E.g., in a class which mixes in CrossCase, defining a method which is called foo_bar will also create an alias for that method called fooBar.

I wrote this module because I prefer camelCased method names, but also wish to respect the preferences of my fellow Rubyists for whom such practices are an abomination. And I’m too lazy to type

alias :twinkle_twinkle :twinkleTwinkle

for every method. It’s all about laziness. Or perhaps I’m catering to my hubris. Or both; I’ll shut up now.

Caveats

This module uses the method_added and singleton_method_added hooks to generate aliases for new methods. If either or both of these methods are already defined, they will be preserved as aliases when the Class or Module is extended. It’s up to you to return the favor should you create your own hook after this module is mixed in to your class.

Author(s)

Thanks

More Information

You can find more information about this module, including any updates, at its project page:

http://www.deveiate.org/code/CrossCase.shtml

Class Method Summary collapse

Class Method Details

.extend_object(mod) ⇒ Object

Object-extension callback – installs aliases for any currently-extant class or instance methods, and installs callbacks that will create aliases for any subsequently-defined methods. Raises an error if any object except a Class or Module is extended.

Raises:

  • (TypeError)


109
110
111
112
113
114
115
116
117
# File 'lib/mega/crosscase.rb', line 109

def self::extend_object( mod )
    raise TypeError, "Expected a Module or a Class, got a " +
        mod.class.name unless
        mod.is_a?( Module )

    self::transformClassMethods( mod )
    self::transformInstanceMethods( mod )
    self::installMethodHooks( mod )
end

.findTargetMethods(*methodList) ⇒ Object

Find methods in the given methodList which are candidates for aliasing.



198
199
200
201
202
203
204
# File 'lib/mega/crosscase.rb', line 198

def self::findTargetMethods( *methodList )
  methodList.flatten.each {|meth|
    next if /(singleton_)?method_added/ =~ meth
    transformedName = transform( meth ) or next
    yield( meth, transformedName )
  }
end

.included(mod) ⇒ Object

The inclusion callback – uses the Ouroboros trick to extend including classes.



100
101
102
# File 'lib/mega/crosscase.rb', line 100

def self::included( mod )
    mod.extend( self )
end

.installAlias(mod, meth, aliasName) ⇒ Object

Install an alias aliasName for the given instance method meth of the Class or Module mod.



189
190
191
192
193
# File 'lib/mega/crosscase.rb', line 189

def self::installAlias( mod, meth, aliasName )
  unless mod.instance_methods(true).include?( aliasName )
    mod.module_eval %{alias_method :#{aliasName}, :#{meth}}
  end
end

.installClassAlias(mod, meth, aliasName) ⇒ Object

Install an alias aliasName for the given class method meth of the Class or Module mod.



168
169
170
171
172
173
174
175
# File 'lib/mega/crosscase.rb', line 168

def self::installClassAlias( mod, meth, aliasName )
  unless mod.respond_to?( aliasName )
    code = %{
      class << self; alias_method( :#{aliasName}, :#{meth} ); end
    }
    mod.module_eval( code, __FILE__, __LINE__ )
  end
end

.installMethodHooks(mod) ⇒ Object

Install method_added and singleton_method_added hooks into the given Module mod which auto-generate aliases for new methods.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/mega/crosscase.rb', line 122

def self::installMethodHooks( mod )
  mod.module_eval {
    class << self
      if respond_to?( :singleton_method_added )
        alias :__cc_sma :singleton_method_added
      end
      def singleton_method_added( id )
        if aliasName = CrossCase::transform( id )
          CrossCase::installClassAlias( self, id, aliasName )
        end
        if respond_to?( :__cc_sma )
          __cc_sma( id )
        else
          super
        end
      end

      if respond_to?( :method_added )
        alias :__cc_ma :method_added
      end                    
      def method_added( id )
        if aliasName = CrossCase::transform( id )
            CrossCase::installAlias( self, id, aliasName )
        end
        if respond_to?( :__cc_ma )
            __cc_ma( id )
        else
            super
        end
      end
    end
  }
end

.transform(mid) ⇒ Object

Return an alternate name for the given method id mid. If the method id is an under_barred method, returns a camelCased version, and vice-versa. If no alternate is called for, returns nil.



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/mega/crosscase.rb', line 210

def self::transform( mid )
  methodName = mid.to_s
  transformedName = ''

  # camelCased methods
  if /[A-Z]/.match( methodName ) && !/_/.match( methodName )
    transformedName = methodName.gsub( /([a-z0-9])([A-Z])/ ) {|match|
        $1 + '_' + $2
    }.downcase
      
  # underbarred_methods
  elsif !/A-Z/.match( methodName ) && /[a-z0-9]_[a-z]/.match( methodName )
    transformedName = methodName.gsub( /([a-z0-9])_([a-z])/ ) {|match|
        $1 + $2.upcase
    }

  else
    transformedName = nil
  end
  
  return transformedName
end

.transformClassMethods(mod) ⇒ Object

Search for and install aliases for either underbarred or camelCased class methods for mod (a Class or Module).



159
160
161
162
163
# File 'lib/mega/crosscase.rb', line 159

def self::transformClassMethods( mod )
  self::findTargetMethods( mod.singleton_methods(false) ) {|meth, aliasName|
      self::installClassAlias( mod, meth, aliasName )
  }
end

.transformInstanceMethods(mod) ⇒ Object

Search for and install aliases for either underbarred or camelCased instance methods for mod (a Class or Module).



180
181
182
183
184
# File 'lib/mega/crosscase.rb', line 180

def self::transformInstanceMethods( mod )
  self::findTargetMethods( mod.instance_methods(false) ) {|meth, aliasName|
    self::installAlias( mod, meth, aliasName )
  }
end