1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 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 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | # -*- Ruby -*-
#
# Legalese: this code is licensed under the GPL v2.
#
# This is an hack to the rails'Inflector that extends the
# rails default table name <-> model name english convention
# using a set of translations from the model name to the
# singular and plural, non-english, form.
#
# You can also select whether to put the string "id" as a prefix
# or a suffix of the translated word, by setting
# Inflector.translated_id_position as :after or :before.
#
# ActiveRecord::Base#undecorated_table_name is also overwritten,
# because it doesn't call Inflector#tableize but rather reimplements
# it instead.
#
# Lastly, you gain two more string and inflector methods
# foreign_key? and foreign_class.
#
# Usage:
# save this file into lib/inflector_translations.rb (or whatever name you like)
#
# put in config/environment.rb:
# --8<-------------------------------------->8--
# require 'inflector_translations'
#
# Inflector.inflections do |inflect|
# inflect.translate 'product', 'prodotto', 'prodotti'
# inflect.translate 'type', 'tipologia', 'tipologie'
# inflect.translate 'order', 'ordine', 'ordini'
# end
#
# Inflector.translated_id_position = :before (or :after)
#
# --8<-------------------------------------->8--
#
# >> Type.table_name
# => "tipologie"
#
# >> Type.name.foreign_key
# => "id_tipologia"
#
# >> Inflector.translated_id_position = :after
# => :after
#
# >> Type.name.foreign_key
# => "tipologia_id"
#
# Now you can remove many of the burden from your models:
#
# class Product < ActiveRecord::Base
# set_table_name 'prodotti'
# belongs_to :type, :foreign_key => 'id_tipologia'
# has_many :orders, :foreign_key => 'id_prodotto'
# end
#
# becomes a typical rails model, with convention and without configuration
#
# class Product < ActiveRecord::Base
# belongs_to :type
# has_many :orders
# end
#
# --
# Marcello Barnaba <vjt@openssl.it>
#
module Inflector
module_eval {
attr_accessor :translated_id_position
@translated_id_position = :before
}
# Returns the given string removing any 'id' prefix or suffix,
# changing underscores into spaces and Capitalizing the result
#
def humanize(lower_case_and_underscored_word)
remove_id(lower_case_and_underscored_word.to_s).gsub(/_/, " ").capitalize
end
# Returns a table name inferred from the given word, by removing
# any ModuleName:: prefixes, transforming CamelCase into under_score
# and singularizing or pluralizing, as given in the second argument.
#
# This method checks for and applies previously defined translations.
#
def tableize(word, plural = true)
word = underscore(demodulize(word))
tran = plural ? :pluralize : :singularize
inflections.find_translation(singularize(word), tran) || self.send(tran, word)
end
# Checks whether the given word looks like a foreign key column name
#
def foreign_key?(word)
word = underscore(word)
[/\w+_id$/, /^id_\w+/].find { |re| re.match(word) } ? true : false
end
# Returns a foreign key column name for the given word.
# This method checks for and applies previously defined translations.
#
alias_method :orig_foreign_key, :foreign_key #:nodoc:
def foreign_key(word, separate_class_name_and_id_with_underscore = true)
if tran = inflections.find_translation(underscore(word))
_ = separate_class_name_and_id_with_underscore ? '_' : ''
translated_id_position == :before ? "id#{_}#{tran}" : "#{tran}#{_}id"
else
orig_foreign_key(word, separate_class_name_and_id_with_underscore)
end
end
# Tries to instantiate the model class referenced by the given foreign
# key.
#
def foreign_class(word)
word = remove_id(underscore(word))
constantize(camelize(inflections.find_translated(word) || singularize(word)))
end
protected
def remove_id(word)
word.gsub(translated_id_position == :after ? /_id$/ : /^id_/, '')
end
inflections.instance_eval { @translations = [] }
class Inflections
attr_reader :translations
# Insert a new translation. Give the word in singular form.
#
def translate(word, singular, plural)
@translations.insert(0,
[word.underscore, {:singularize => singular, :pluralize => plural}])
end
# Returns given word's translation, either singular or plural
#
def find_translation(word, transformation = :singularize)
if tran = @translations.find { |w, sp| w == word }
tran[1][transformation]
end
end
# Returns english translation of given word
#
def find_translated(word)
if tran = @translations.find { |w, sp| sp.values.include?(word) }
tran[0]
end
end
end
end
# Added String#foreign_key? and String#foreign_class, which call
# the respective Inflector's method passing self as the first
# parameter.
#
class String
[:foreign_key?, :foreign_class].each { |meth|
define_method(meth) { Inflector.send(meth, self) }
}
end
# Overwrite ActiveRecord::Base#undecorated_table_name with
# a facade around Inflector#tableize
#
module ActiveRecord
class Base
class << self
private
def undecorated_table_name(class_name = base_class.name)
Inflector.tableize(class_name, pluralize_table_names)
end
end
end
end
# EOF |