i18n-inflector-rails 0.1.0

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.
@@ -0,0 +1,185 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Author:: Paweł Wilk (mailto:pw@gnu.org)
4
+ # Copyright:: (c) 2011 by Paweł Wilk
5
+ # License:: This program is licensed under the terms of {file:LGPL-LICENSE GNU Lesser General Public License} or {file:COPYING Ruby License}.
6
+ #
7
+ # This file contains I18n::Backend::Inflector::Rails module,
8
+ # which extends ActionView::Helpers::TranslationHelper
9
+ # by adding the ability to interpolate patterns containing
10
+ # inflection tokens defined in translation data.
11
+
12
+ module I18n
13
+ module Inflector
14
+ module Rails
15
+
16
+ # This module contains instance methods for ActionController.
17
+ module InstanceMethods
18
+
19
+ # This method calls the class method {I18n::Inflector::Rails::ClassMethods#i18n_inflector_methods}
20
+ def i18n_inflector_methods
21
+ self.class.i18n_inflector_methods
22
+ end
23
+
24
+ # @private
25
+ def self.included(base)
26
+ base.helper_method(:i18n_inflector_methods)
27
+ end
28
+
29
+ end # instance methods
30
+
31
+ # This module contains class methods for ActionController.
32
+ module ClassMethods
33
+
34
+ # This method reads the internal Hash +i18n_inflector_methods+ containing registered
35
+ # inflection methods and the assigned kinds. It also reads any methods
36
+ # assignments that were defined earlier in the inheritance path and
37
+ # merges them with current results; the most current entries will
38
+ # override the entries defined before.
39
+ #
40
+ # @api public
41
+ # @return [Hash] the Hash containing assignments made by using {inflection_method}
42
+ def i18n_inflector_methods
43
+ prev = superclass.respond_to?(:i18n_inflector_methods) ? superclass.i18n_inflector_methods : {}
44
+ return @i18n_inflector_methods.nil? ? prev : prev.merge(@i18n_inflector_methods)
45
+ end
46
+
47
+ # This method allows to assign methods (typically attribute readers)
48
+ # to inflection kinds that are defined in translation files and
49
+ # supported by {I18n::Inflector} module. Methods registered like that
50
+ # will be tracked when {translate} is used and their returning values will be
51
+ # passed as inflection options along with assigned kinds. If the kind is not
52
+ # given then method assumes that the name of a kind is the same as the given
53
+ # name of a method.
54
+ #
55
+ # @api public
56
+ # @note Any added method will become helper!
57
+ # @raise [I18n::Inflector::Rails::BadInflectionMethod] when name or value is malformed
58
+ # @param [Hash,Array,Symbol,String] assignment the methods and inflection kinds assigned to them
59
+ # @return [void]
60
+ # @yield [method, kind, value, caller] optional block that will be executed
61
+ # each time the registered method is called. Its result will replace
62
+ # the original returning value of the method that is assigned to a kind
63
+ # @yieldparam [Symbol] method the name of an assigned method
64
+ # @yieldparam [Symbol] kind the name of an inflection kind assigned to that +method+
65
+ # @yieldparam [Object] value the original result of calling the +method+ that will be assigned to a +kind+ as a token
66
+ # @yieldparam [Object] caller the object that made a call to {translate} method
67
+ # @yieldreturn [String] the new +value+ (token name) that will be assigned to a +kind+
68
+ def inflection_method(assignment, &block)
69
+ if assignment.is_a?(Array)
70
+ new_assignment = {}
71
+ assignment.flatten.each{|e| new_assignment[e]=new_assignment}
72
+ assignment = new_assignment
73
+ elsif (assignment.is_a?(String) || assignment.is_a?(Symbol))
74
+ assignment = { assignment => assignment }
75
+ end
76
+
77
+ if (assignment.nil? || !assignment.is_a?(Hash) || assignment.empty?)
78
+ raise I18n::Inflector::Rails::BadInflectionMethod.new(assignment)
79
+ end
80
+
81
+ @i18n_inflector_methods ||= {}
82
+ assignment.each_pair do |k,v|
83
+ k = k.to_s
84
+ v = v.to_s
85
+ if (k.empty? || v.empty?)
86
+ raise I18n::Inflector::Rails::BadInflectionMethod.new("#{k.inspect} => #{v.inspect}")
87
+ end
88
+ k = k.to_sym
89
+ helper_method(k)
90
+ @i18n_inflector_methods[k] ||= {}
91
+ @i18n_inflector_methods[k][:kind] = v.to_sym
92
+ @i18n_inflector_methods[k][:proc] = block
93
+ end
94
+ end
95
+ alias_method :inflection_methods, :inflection_method
96
+
97
+ # This method allows to remove methods from sets
98
+ # created using {inflection_method}. It is useful
99
+ # when there is a need to break inheritance in some controller,
100
+ # but a method has been marked as inflection method by
101
+ # a parrent class.
102
+ #
103
+ # @api public
104
+ # @raise [I18n::Inflector::Rails::BadInflectionMethod] when name or value is malformed
105
+ # @param [Array] names the method names that should be marked as removed in this controller
106
+ # @return [void]
107
+ def no_inflection_method(*names)
108
+ names = names.flatten
109
+ if (names.nil? || names.empty?)
110
+ raise I18n::Inflector::Rails::BadInflectionMethod.new(names)
111
+ end
112
+ @i18n_inflector_methods ||= {}
113
+ names.each do |meth|
114
+ unless (meth.is_a?(Symbol) || meth.is_a?(String))
115
+ raise I18n::Inflector::Rails::BadInflectionMethod.new(meth)
116
+ end
117
+ meth = meth.to_s
118
+ raise I18n::Inflector::Rails::BadInflectionMethod.new(meth) if meth.empty?
119
+ @i18n_inflector_methods[meth.to_sym] = nil
120
+ end
121
+ end
122
+ alias_method :no_inflection_methods, :no_inflection_method
123
+
124
+ end # class methods
125
+
126
+ # This module contains a version of {translate} method that
127
+ # tries to use +i18n_inflector_methods+ available in the current context.
128
+ # The method from this module will wrap the
129
+ # {ActionView::Helpers::TranslationHelper#translate} method.
130
+ module InflectedTranslate
131
+
132
+ # This method tries to feed itself with the data coming
133
+ # from +i18n_inflector_methods+ available in the current context.
134
+ # The data from the last method should contain options
135
+ # of inflection pairs (<tt>kind => value</tt>) that will
136
+ # be passed to {I18n::Backend::Inflector#translate} through
137
+ # {ActionView::Helpers::TranslationHelper#translate}.
138
+ #
139
+ # @api public
140
+ # @param [String] key translation key
141
+ # @param [Hash] options a set of options to pass to the
142
+ # translation routines
143
+ # @return [String] the translated string with inflection patterns
144
+ # interpolated
145
+ def translate(*args)
146
+ test_locale = args.last.is_a?(Hash) ? args.last[:locale] : nil
147
+ test_locale ||= I18n.locale
148
+ return super unless I18n.backend.inflector.inflected_locale?(test_locale)
149
+
150
+ # collect inflection variables that are present in this context
151
+ subopts = t_prepare_inflection_options
152
+
153
+ # jump to original translate if no variables are present
154
+ return super if subopts.empty?
155
+
156
+ options = args.last.is_a?(Hash) ? args.pop : {}
157
+ args.push subopts.merge(options)
158
+ super
159
+ end
160
+
161
+ alias_method :t, :translate
162
+
163
+ protected
164
+
165
+ # This method tries to read +i18n_inflector_methods+ available in the current context.
166
+ #
167
+ # @return [Hash] the inflection options (<tt>kind => value</tt>)
168
+ def t_prepare_inflection_options
169
+ subopts = {}
170
+ i18n_inflector_methods.each_pair do |m, obj|
171
+ next if obj.nil?
172
+ value = method(m).call
173
+ proca = obj[:proc]
174
+ kind = obj[:kind]
175
+ value = proca.call(m, kind, value, self) unless proca.nil?
176
+ subopts[kind] = value.to_s
177
+ end
178
+ return subopts
179
+ end
180
+
181
+ end # Translate
182
+
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Author:: Paweł Wilk (mailto:pw@gnu.org)
4
+ # Copyright:: (c) 2011 by Paweł Wilk
5
+ # License:: This program is licensed under the terms of {file:LGPL-LICENSE GNU Lesser General Public License} or {file:COPYING Ruby License}.
6
+ #
7
+ # This file loads I18n::Inflector::Rails goodies into Rails.
8
+
9
+ module I18n
10
+ module Inflector
11
+ module Rails
12
+
13
+ class Railtie < ::Rails::Engine
14
+
15
+ initializer :before_initialize do
16
+ ActionController::Base.send(:extend, I18n::Inflector::Rails::ClassMethods)
17
+ ActionController::Base.send(:include, I18n::Inflector::Rails::InstanceMethods)
18
+ end
19
+
20
+ initializer :after_initialize do
21
+ ActionController::Base.helper I18n::Inflector::Rails::InflectedTranslate
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Author:: Paweł Wilk (mailto:pw@gnu.org)
4
+ # Copyright:: (c) 2011 by Paweł Wilk
5
+ # License:: This program is licensed under the terms of {file:LGPL-LICENSE GNU Lesser General Public License} or {file:COPYING Ruby License}.
6
+ #
7
+ # This file contains version information.
8
+
9
+ module I18n
10
+ module Inflector
11
+ module Rails
12
+
13
+ # @private
14
+ DEVELOPER = 'Paweł Wilk'
15
+ # @private
16
+ EMAIL = 'pw@gnu.org'
17
+ # @private
18
+ VERSION = '0.1.0'
19
+ # @private
20
+ NAME = 'i18n-inflector-rails'
21
+ # @private
22
+ SUMMARY = 'I18n Inflector bindings for Rails'
23
+ # @private
24
+ URL = 'https://rubygems.org/gems/i18n-inflector-rails/'
25
+ # @private
26
+ DESCRIPTION = 'This plug-in provides I18n Inflector module bindings for Rails.'
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,201 @@
1
+ require 'spec_helper'
2
+
3
+ class ApplicationController < ActionController::Base; end
4
+ class InflectedTranslateController < ApplicationController; end
5
+
6
+ describe ApplicationController do
7
+
8
+ before do
9
+
10
+ I18n.locale = :xx
11
+ I18n.backend.store_translations(:xx, :i18n => { :inflections => {
12
+ :gender => {
13
+ :m => 'male',
14
+ :f => 'female',
15
+ :n => 'neuter',
16
+ :s => 'strange',
17
+ :masculine => '@m',
18
+ :feminine => '@f',
19
+ :neuter => '@n',
20
+ :neutral => '@neuter',
21
+ :default => 'neutral' },
22
+ :person => {
23
+ :i => 'I',
24
+ :you => 'You',
25
+ :it => 'It'}
26
+ } })
27
+ I18n.backend.store_translations(:xx, 'welcome' => 'Dear @{f:Lady|m:Sir|n:You|All}!')
28
+ I18n.backend.store_translations(:xx, 'to_be' => 'Oh @{i:I am|you:You are|it:It is}')
29
+
30
+ end
31
+
32
+ describe ".inflection_method" do
33
+
34
+ before do
35
+ class AnotherController < InflectedTranslateController; end
36
+ end
37
+
38
+ it "should be albe to assign a mehtod to the inflection kind" do
39
+ lambda{AnotherController.inflection_method(:users_gender => :gender)}.should_not raise_error
40
+ end
41
+
42
+ it "should be albe to accept single Symbol argument" do
43
+ lambda{AnotherController.inflection_method(:time)}.should_not raise_error
44
+ end
45
+
46
+ it "should be albe to accept single String argument" do
47
+ lambda{AnotherController.inflection_method('time')}.should_not raise_error
48
+ end
49
+
50
+ it "should be albe to accept Array<Symbol> argument" do
51
+ lambda{AnotherController.inflection_method([:time])}.should_not raise_error
52
+ end
53
+
54
+ it "should be albe to assign a mehtod to the inflection kind with proc" do
55
+ lambda{AnotherController.inflection_method(:users_gender => :gender){|a,b,c,d,e| :m} }.should_not raise_error
56
+ lambda{AnotherController.inflection_method(:time){|a,b,c,d,e| :m} }.should_not raise_error
57
+ end
58
+
59
+ it "should raise an error when method name is wrong" do
60
+ lambda{AnotherController.inflection_method}.should raise_error
61
+ lambda{AnotherController.inflection_method(nil => :blabla)}.should raise_error
62
+ lambda{AnotherController.inflection_method(:blabla => nil)}.should raise_error
63
+ lambda{AnotherController.inflection_method({''=>''})}.should raise_error
64
+ lambda{AnotherController.inflection_method(nil => nil)}.should raise_error
65
+ lambda{AnotherController.inflection_method(nil)}.should raise_error
66
+ lambda{AnotherController.inflection_method([nil])}.should raise_error
67
+ lambda{AnotherController.inflection_method([''])}.should raise_error
68
+ lambda{AnotherController.inflection_method([])}.should raise_error
69
+ lambda{AnotherController.inflection_method({})}.should raise_error
70
+ end
71
+
72
+ end
73
+
74
+ describe ".no_inflection_method" do
75
+
76
+ before do
77
+ class AnotherController < InflectedTranslateController; end
78
+ end
79
+
80
+ it "should be albe to spit a mehtod of the inflection kind" do
81
+ lambda{AnotherController.no_inflection_method(:users_gender)}.should_not raise_error
82
+ end
83
+
84
+ it "should be albe to accept single Symbol argument" do
85
+ lambda{AnotherController.no_inflection_method(:time)}.should_not raise_error
86
+ end
87
+
88
+ it "should be albe to accept single String argument" do
89
+ lambda{AnotherController.no_inflection_method('time')}.should_not raise_error
90
+ end
91
+
92
+ it "should be albe to accept Array<Symbol> argument" do
93
+ lambda{AnotherController.no_inflection_method([:time])}.should_not raise_error
94
+ end
95
+
96
+ it "should raise an error when method name is wrong" do
97
+ lambda{AnotherController.no_inflection_method}.should raise_error
98
+ lambda{AnotherController.no_inflection_method(nil)}.should raise_error
99
+ lambda{AnotherController.no_inflection_method([nil])}.should raise_error
100
+ lambda{AnotherController.no_inflection_method([''])}.should raise_error
101
+ lambda{AnotherController.no_inflection_method([])}.should raise_error
102
+ lambda{AnotherController.no_inflection_method({})}.should raise_error
103
+ end
104
+
105
+ end
106
+
107
+ describe ".i18n_inflector_methods" do
108
+
109
+ before do
110
+ InflectedTranslateController.inflection_method(:users_gender => :gender)
111
+ InflectedTranslateController.inflection_method(:time)
112
+ @expected_hash = {:users_gender=>{:kind=>:gender, :proc=>nil},
113
+ :time=>{:kind=>:time, :proc=>nil}}
114
+ end
115
+
116
+ it "should be callable" do
117
+ lambda{InflectedTranslateController.i18n_inflector_methods}.should_not raise_error
118
+ end
119
+
120
+ it "should be able to read methods assigned to inflection kinds" do
121
+ InflectedTranslateController.i18n_inflector_methods.should == @expected_hash
122
+ end
123
+
124
+ end
125
+
126
+ describe "controller instance methods" do
127
+
128
+ before do
129
+
130
+ class InflectedTranslateController
131
+ inflection_method :users_gender => :gender
132
+ def users_gender; :m end
133
+ def time; :present end
134
+ def translated_male; translate('welcome') end
135
+ def t_male; t('welcome') end
136
+ end
137
+
138
+ class InflectedLambdedController < InflectedTranslateController
139
+ inflection_method(:person) {:it}
140
+ def person; :you end
141
+ def translated_person; translate('to_be') end
142
+ end
143
+
144
+ class InflectedLambdedPrimController < InflectedLambdedController
145
+ inflection_method :person
146
+ end
147
+
148
+ @controller = InflectedTranslateController.new
149
+ @person_controller = InflectedLambdedController.new
150
+ @personprim_controller = InflectedLambdedPrimController.new
151
+
152
+ @expected_hash = {:users_gender=>{:kind=>:gender, :proc=>nil},
153
+ :time=>{:kind=>:time, :proc=>nil}}
154
+
155
+ end
156
+
157
+ describe "#i18n_inflector_methods" do
158
+
159
+ it "should be able to read methods assigned to inflection kinds" do
160
+ @controller.i18n_inflector_methods.should == @expected_hash
161
+ end
162
+
163
+ end
164
+
165
+ describe "#translate" do
166
+
167
+ it "should translate using inflection patterns and pick up the right value" do
168
+ @controller.translated_male.should == 'Dear Sir!'
169
+ end
170
+
171
+ it "should make use of blocks if assigned to inflection methods" do
172
+ @person_controller.translated_person.should == 'Oh It is'
173
+ end
174
+
175
+ it "should make use of inherited inflection method assignments" do
176
+ @person_controller.translated_male.should == 'Dear Sir!'
177
+ end
178
+
179
+ it "should make use of overriden inflection method assignments" do
180
+ @personprim_controller.translated_person.should == 'Oh You are'
181
+ end
182
+
183
+ it "should make use of disabled inflection method assignments" do
184
+ InflectedLambdedPrimController.no_inflection_method :person
185
+ @personprim_controller.translated_person.should == 'Oh '
186
+ @person_controller.translated_person.should == 'Oh It is'
187
+ end
188
+
189
+ end
190
+
191
+ describe "#t" do
192
+
193
+ it "should call translate" do
194
+ @controller.t_male.should == 'Dear Sir!'
195
+ end
196
+
197
+ end
198
+
199
+ end
200
+
201
+ end
@@ -0,0 +1,2 @@
1
+ require 'rspec/core'
2
+ require 'i18n-inflector-rails'