i18n-inflector-rails 0.1.0

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