Module: Babylonia::ClassMethods

Defined in:
lib/babylonia/class_methods.rb

Overview

Class methods to extend a class with in order to make it able to handle translatable attributes

Since:

  • 0.0.1

Instance Method Summary collapse

Instance Method Details

#build_babylonian_tower_on(*fields) ⇒ Object

Main class method ob Babylonia. Use to make attributes translatable

Parameters:

  • fields (Symbol)

    the attributes to translate

  • options (Hash)

    The options for translation

  • [Symbol, (Hash)

    a customizable set of options

  • [Boolean] (Hash)

    a customizable set of options

  • [String] (Hash)

    a customizable set of options

Since:

  • 0.0.1



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
# File 'lib/babylonia/class_methods.rb', line 36

def build_babylonian_tower_on(*fields)
  babylonian_options = fields.last.is_a?(Hash) ? fields.pop : {}
  add_to_handled_babylonian_fields fields
  babylonian_options[:locale]          ||= lambda { |r, f| I18n.locale }
  babylonian_options[:default_locale]  ||= lambda { |r, f| I18n.default_locale }
  babylonian_options[:available_locales] ||= lambda { |r, f| I18n.available_locales }
  babylonian_options[:fallback]        = true if babylonian_options[:fallback].nil?
  
  fields.each do |field|
    instance_variable_set(:"@babylonian_options_for_#{field}", babylonian_options)
    
    # Alias method chain the field to a translated value
    # @param [Symbol] locale Pass a locale to get the field translation in this specific locale
    # @return [String, NilClass] Either the string with the translation, the fallback, the placeholder or nil
    # @example Call a field in italian
    #   your_instance.field(:it) #=> "Translation" 
    #
    define_method :"#{field}_translated" do |locale=nil|
      field_hash    = send(:"#{field}_hash")
      translation   = field_hash[locale || evaluate_babylonian_option!(:locale, field)]
      translation   = field_hash[evaluate_babylonian_option!(:default_locale, field)] if (translation.nil? or translation.empty?) and evaluate_babylonian_option!(:fallback, field)
      (translation.nil? or translation.empty?) ? evaluate_babylonian_option!(:placeholder, field) : translation
    end
    alias_method :"#{field}_raw", field
    alias_method field, :"#{field}_translated"
    
    # Return the translated values as a hash
    # @return [Hash] The hash with all the translations stored in the field
    #
    define_method :"#{field}_hash" do
      field_content = send(:"#{field}_raw")
      field_content.is_a?(String) ? YAML.load(field_content) : {}
    end
    
    # Return all the languages stored
    # @return [Array] An array containing all languages stored in the field
    #
    define_method :"#{field}_languages" do
      send(:"#{field}_hash").keys
    end
    
    define_method :has_translated_attribute? do |attr|
      self.class.handled_babylonian_fields.include?(attr.to_sym)
    end
    
    # Return if a translation in the language is stored for the field
    # @return [Boolean] True if a translation is stored
    #
    define_method :"#{field}_has_locale?" do |locale|
      send(:"#{field}_languages").include?(locale.to_sym)
    end
    
    # Return if a locale is theoretically available for the field
    # @return [Boolean] True if the language is available
    #
    define_method :"#{field}_has_available_locale?" do |locale|
      evaluate_babylonian_option!(:available_locales, field).include?(locale.to_sym)
    end
    
    # Set the field to a value. This either takes a string or a hash
    # If given a String, the current locale is set to this value
    # If given a Hash, the hash is merged into the current translation hash, and empty values are purged
    # @param [String, Hash] data The data to set either the current language translation or all translations to
    # @example Set the translation for the current locale
    #   your_object.field = "TRANSLATION"
    # @example Set the translation and delete italian
    #   your_object.field = {de: 'DEUTSCH', it: ''}
    #
    define_method :"#{field}_translated=" do |data|
      current_hash = send(:"#{field}_hash")
      
      if data.is_a?(String)
        current_hash.merge! evaluate_babylonian_option!(:locale, field) => data
      elsif data.is_a?(Hash)
        data.delete_if{|k,v| !send(:"#{field}_has_available_locale?", k) }
        current_hash.merge! data
      end
      
      send(:"#{field}_raw=", YAML.dump(current_hash.delete_if{|k,v| v.nil? || v.empty? }))
    end
    alias_method :"#{field}_raw=", :"#{field}="
    alias_method :"#{field}=", :"#{field}_translated="
  end
  
  # Define method missing to be able to access a language directly
  define_method :method_missing do |meth, *args, &block|
    if (m = meth.to_s.match(/\A([^_]+)_(\w+)(=)?\z/).to_a[1..3]) && has_translated_attribute?(m[0]) && send(:"#{m[0]}_has_available_locale?", m[1])
      send(m[0] + m[2].to_s, m[2] ? {m[1].to_sym => args.first} : m[1].to_sym)
    else
      super(meth, *args, &block)
    end
  end
  
  define_method :evaluate_babylonian_option! do |option, field, recursion=false|
    options = self.class.instance_variable_get :"@babylonian_options_for_#{field}"

    o = options[option]
    if o.is_a?(Proc)
      o.call self, field
    elsif o.is_a?(Symbol) && (recursion || !evaluate_babylonian_option!(:available_locales, field, true).include?(o))
      send o
    else
      o
    end
  end
end

#handled_babylonian_fieldsObject

Store all handled fields in a class instance variable

Since:

  • 0.0.1



24
25
26
# File 'lib/babylonia/class_methods.rb', line 24

def handled_babylonian_fields
  instance_variable_get(:@handled_babylonian_fields) || instance_variable_set(:@handled_babylonian_fields, [])
end