t_t 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cc0178a11cfb6485afd79658204c099a1669b9e2
4
- data.tar.gz: 5b2fe90809f3c1ecc26dfa80c31b7ae54d104c50
3
+ metadata.gz: d836d08bfcb2cd0c0ddc4cf71c7ff13bc8d95aba
4
+ data.tar.gz: 46616d020eef370af7a34e6dd672262be6dcf477
5
5
  SHA512:
6
- metadata.gz: 2bf34f3f4efb00014850798c385233ce27c9956a9867080d9c4cdc0141052d3ec3d6bbbbe66922e4be2f933a52fc758566e8e912adb6c9306b6e740ed221c5eb
7
- data.tar.gz: 157cedeec1cbcab34a82d77a5d70844aea77193bde81d2d5f9272f304f68c580a49c879a4fde8169eada2a8307eb58f90fce50a9d01e6d4f9aa2b66b657fda7f
6
+ metadata.gz: 8b0904544cbcce8598217fae39dacc61a7c2940298f9f096a1e24ff36828b06a756fdceef79f01aeafccbc20580ebd49018ee6f72e7a8d52ee0af9db18b4bb91
7
+ data.tar.gz: d16e1835b588593536162b9dd9aa5541dcf9ea8bdc672d7de552f172fefdcc8231e354c9435adf85a893f386b3a1f5475bc62e5eeb70a937c4f47db753d958dd
@@ -0,0 +1,15 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - rbx-2
4
+ - jruby
5
+ - 2.0.0
6
+ - 2.1
7
+ - 2.2
8
+ - ruby-head
9
+ gemfile:
10
+ - gemfiles/Gemfile.actionpack-3.1.x
11
+ - gemfiles/Gemfile.actionpack-3.2.x
12
+ - gemfiles/Gemfile.actionpack-4.0.x
13
+ - gemfiles/Gemfile.actionpack-4.1.x
14
+ - gemfiles/Gemfile.actionpack-4.2.x
15
+ - Gemfile
@@ -0,0 +1,307 @@
1
+ # Dos-T cheatsheet
2
+
3
+ ## Commons
4
+ The **widely used words** across the application such as "Back", "Cancel", "Save" are the prime candidates to put in **common**:
5
+
6
+ ```ruby
7
+ # en:
8
+ # common:
9
+ # back: "Back"
10
+
11
+ tt.c :back # => "Back"
12
+ ```
13
+
14
+ Time to time there is a need to **override commons** for a section (controller in rails environment). To do so, just **add 'common' sub-key** in the section translations:
15
+
16
+ ```ruby
17
+ # en:
18
+ # common:
19
+ # copy: "Copy"
20
+ # users:
21
+ # common:
22
+ # copy: "Duplicate"
23
+
24
+ # app/views/documents/index.haml
25
+ = tt.c :copy # => "Copy"
26
+
27
+ # app/views/users/index.haml
28
+ = tt.c :copy # => "Duplicate"
29
+ ```
30
+
31
+ ## Attributes
32
+
33
+ You probably know that `active_model` based classes have handy method **#human_attribute_name**. The main problems with it are the long method name and `humanization` on translation missing. The gem provides an **almost compatible equivalent #attr**.
34
+
35
+ ```ruby
36
+ # en:
37
+ # attributes:
38
+ # base:
39
+ # email: "Email"
40
+ # user:
41
+ # email: "Login / Email"
42
+
43
+ # app/views/subscriptions/index.haml
44
+ # a base translation
45
+ tt.attr :email, :subscription # => "Email"
46
+
47
+ # app/views/users/index.haml
48
+ # a specific translation
49
+ tt.attr :email, :user # => "Login / Email"
50
+
51
+ # with 'current model reflection' (preferred): UsersController => :user
52
+ tt.attr :email # => "Login / Email"
53
+ ```
54
+
55
+ `#attr` also looks into orm translations paths. If you place translations according to `active_record`:
56
+
57
+ ```ruby
58
+ # en:
59
+ # activerecord:
60
+ # attributes:
61
+ # user:
62
+ # email: "Login / Email"
63
+ # attributes:
64
+ # user: "Email"
65
+
66
+ tt.c :email, :user # => "Login / Email"
67
+ ```
68
+ For other `active_model` based orms please specify configuration in an initializator:
69
+
70
+ ```ruby
71
+ # en:
72
+ # mongoid:
73
+ # attributes:
74
+ # user:
75
+ # email: "Login / Email"
76
+ # attributes:
77
+ # user: "Email"
78
+
79
+ # app/config/tt.rb
80
+ TT.config(prefix: :mongoid)
81
+ ```
82
+ ## Resources
83
+
84
+ There is another translation hard-to-use feature which are present in `active_model` - **.model_name.human**. It
85
+ returns a translated human name of a model. To get a plural version you should also provide the `count: 10` parameter.
86
+ With Dos-T you get two short methods which do the job - **#r** & **#rs** (human resource and resources):
87
+
88
+ ```ruby
89
+ # en:
90
+ # models:
91
+ # user:
92
+ # one: "User"
93
+ # other: "Users"
94
+ # zero: "Userz"
95
+
96
+ tt.r :user # => "User"
97
+ tt.rs :user, 20 # => "Users"
98
+ tt.rs :user, 0 # => "Userz"
99
+
100
+ # app/views/users/show.haml
101
+ # with 'current model reflection' and the default value (10)
102
+ tt.rs # => "Users"
103
+ ```
104
+
105
+ ## Enums
106
+
107
+ Quite often a developer needs to provide a **human translation for the variants** of an enum attribute. Dos-T provides
108
+ a handy method **#enum**:
109
+
110
+ ```ruby
111
+ # en:
112
+ # enums:
113
+ # base:
114
+ # role:
115
+ # a: "Admin"
116
+ # u: "User"
117
+ # subscription:
118
+ # role:
119
+ # c: "Subscriber"
120
+
121
+ # app/views/subscriptions/index.haml
122
+ tt.enum :role, :a, :user # => "Admin"
123
+ tt.enum :role, :c, :subscription # => "Subscriber"
124
+
125
+ # with 'current model reflection'
126
+ tt.enum :role, :u # => "User"
127
+ ```
128
+ You can put enum translations inside orm translation namespace as with `#attr` method.
129
+
130
+ ## Errors
131
+
132
+ Errors are an essential part of any application. Within `active_model` orms you have **errors.full_messages**
133
+ & **errors.full_messages_for** which are fine only for a few use-cases. To make it easier the gem has an
134
+ **almost compatible equivalent #e**:
135
+
136
+ ```ruby
137
+ # en:
138
+ # errors:
139
+ # base:
140
+ # blank: "is blank"
141
+ # greater_than: "must be greater than %{count}"
142
+ # password:
143
+ # blank: "is empty"
144
+ # user:
145
+ # password:
146
+ # blank: "is invalid"
147
+
148
+ # app/views/users/index.haml
149
+ tt.e(:password, :blank, :user) # => "is invalid"
150
+ tt.e(:password, :greater_than, :user, count: 4) # => "must be greater than 4"
151
+
152
+ # with 'current model reflection'
153
+ tt.e(:password, :blank) # => "is invalid"
154
+ tt.e(:password, :greater_than, count: 4) # => "must be greater than 4"
155
+
156
+ tt.e(:password, :blank, :client) # => "is empty"
157
+ tt.e(:name, :blank, :client) # => "is blank"
158
+ ```
159
+
160
+ ## Actions
161
+
162
+ The unique feature of the gem which helps to reduce amount of duplications in flash messages, warnings and other messages
163
+ related to notification about some action on resources. To get the idea let's look into a typical rails controller:
164
+
165
+ ```ruby
166
+ def create
167
+ if user.save
168
+ flash[:notice] = "The user has been created"
169
+ end
170
+ # other code
171
+ end
172
+
173
+ def update
174
+ if user.save
175
+ flash[:notice] = "The user has been updated"
176
+ end
177
+ # other code
178
+ end
179
+
180
+ def destroy
181
+ user.destroy
182
+ flash[:notice] = "The user has been deleted"
183
+ # other code
184
+ end
185
+ ```
186
+
187
+ For one controller the situation looks fine, but a typical application has at least 10 to 15 controllers. As the result
188
+ these translations creates a long translation files with many duplications. To solve the problem method **#a**
189
+ comes on the scene:
190
+
191
+ ```ruby
192
+ # en:
193
+ # actions:
194
+ # create:
195
+ # base: "The %{r} has been created"
196
+ # update:
197
+ # base: "The %{r} has been updated"
198
+ # delete:
199
+ # base: "The %{r} has been deleted"
200
+ # models:
201
+ # user:
202
+ # one: "User"
203
+ # other: "Users"
204
+
205
+ def create
206
+ if user.save
207
+ flash[:notice] = tt.a(:create, :user) # => "The user has been created"
208
+ end
209
+ # other code
210
+ end
211
+
212
+ def update
213
+ if user.save
214
+ flash[:notice] = tt.a(:update, :user) # => "The user has been updated"
215
+ end
216
+ # other code
217
+ end
218
+
219
+ def destroy
220
+ user.destroy
221
+ # with 'current model reflection'
222
+ flash[:notice] = tt.a(:delete) # => "The user has been deleted"
223
+ # other code
224
+ end
225
+ ```
226
+
227
+ As you can see in translation you define a base translation for an action which expected at least the next variables:
228
+ - RS - `tt.rs`
229
+ - R - `tt.r`
230
+ - rs - `tt.rs.downcase`
231
+ - r - `tt.r.downcase`
232
+
233
+ If for some action one of the models should have a custom translation (a business logic, a grammar rule of a language)
234
+ just add a model name key in a action translations:
235
+
236
+ ```ruby
237
+ # en:
238
+ # actions:
239
+ # create:
240
+ # base: "The %{r} has been created"
241
+ # photo: "The %{r} has been uploaded"
242
+
243
+ tt.a(:create, :user) # => "The user has been created"
244
+ tt.a(:create, :photo) # => "The photo has been uploaded"
245
+ ```
246
+ Take a look at [examples folder](./examples/) for a more examples.
247
+
248
+ ## Custom shortcuts
249
+
250
+ As an application grows `common` grows too. To avoid a long list of common words it's good to group them by group.
251
+ For example, words related to a user tips is good to place into `tips`, words related to forms into `forms`. To do it
252
+ the gem provides a configuration block:
253
+
254
+ ```ruby
255
+ # app/config/tt.rb
256
+ TT.config do
257
+ lookup_key_method :tip, :tips
258
+ lookup_key_method :f, :forms
259
+ end
260
+ ```
261
+ As the result your `tt` variable will have `#tip` & `#f` methods which behave like `#c`.
262
+
263
+ ## Advanced usage & configuration
264
+
265
+ Dos-T was designed to be easy-as-possible for the default rails stack, but if you don't have it or don't have rails at
266
+ all it's not a problem. Let's look at a possible cases:
267
+
268
+ ### You don't have ActionPack or want to use Dos-T outside the views
269
+
270
+ `tt` is an instance of `TT::Translator`. To create a variable you need `namespace` & `section` (optional) keys. In the rails
271
+ environment it's `controller_path` and `action_name`.
272
+
273
+ ```ruby
274
+ class EmailApp < Sinatra::Base
275
+ before do
276
+ @tt = TT::Translator.new('emails')
277
+ end
278
+
279
+ post '/' do
280
+ # processing
281
+ { status: tt.t(:handled) }.to_json # { status: I18n.t('emails.handled') }.to_json
282
+ end
283
+ end
284
+
285
+ class EmailSender
286
+ attr_reader :tt
287
+
288
+ def initialize
289
+ @tt = TT::Translator.new('services/email_sender')
290
+ end
291
+
292
+ def work
293
+ each_letter do |letter|
294
+ send_mail(subject: tt.a(:confirm, :email, user: letter.user_name))
295
+ # ...
296
+ end
297
+ end
298
+ end
299
+ ```
300
+
301
+ ### You use different to ActiveRecord orm
302
+
303
+ Just specify an orm i18n scope:
304
+ ```ruby
305
+ # app/config/tt.rb
306
+ TT.config(prefix: :mongoid)
307
+ ```
File without changes
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+ gem 'activesupport', '~> 3.1.0'
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+ gem 'activesupport', '~> 3.2.0'
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+ gem 'activesupport', '~> 4.0.0'
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+ gem 'activesupport', '~> 4.1.0'
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+ gem 'activesupport', '~> 4.2.0'
data/lib/t_t.rb CHANGED
@@ -1,65 +1,185 @@
1
+ require "active_support/inflector"
1
2
  require "active_support/lazy_load_hooks"
3
+ require "active_support/multibyte/chars"
2
4
  require "i18n"
3
5
 
4
6
  module TT
7
+ module Utils
8
+ extend self
9
+
10
+ DOWNCASE = lambda { |str, locale| (locale == :en) ? str.downcase : str.mb_chars.downcase.to_s }
11
+
12
+ def lookup(prefix, base_suffix = :base)
13
+ prefix ? prefix_lookup(prefix, base_suffix) : simple_lookup(base_suffix)
14
+ end
15
+
16
+ def to_parts(str)
17
+ str.to_s.underscore.split(/\.|\//)
18
+ end
19
+
20
+ private
21
+
22
+ def simple_lookup(base_suffix)
23
+ lambda do |ns, type|
24
+ parts = to_parts(ns)
25
+ model_path = parts.join('.')
26
+
27
+ root = "#{ type }.#{ model_path }"
28
+
29
+ defaults = []
30
+ defaults << :"#{ type }.#{ parts.last }" if parts.length > 1
31
+ defaults << :"#{ type }.#{ base_suffix }"
32
+
33
+ [root, defaults]
34
+ end
35
+ end
36
+
37
+ def prefix_lookup(prefix, base_suffix)
38
+ lambda do |ns, type|
39
+ parts = to_parts(ns)
40
+ model_path = parts.join('.')
41
+
42
+ root = "#{ prefix }.#{ type }.#{ model_path }"
43
+ defaults = [:"#{ type }.#{ model_path }"]
44
+
45
+ if parts.length > 1
46
+ pure_model = parts.last
47
+ defaults << :"#{ prefix }.#{ type }.#{ pure_model }"
48
+ defaults << :"#{ type }.#{ pure_model }"
49
+ end
50
+ defaults << :"#{ prefix }.#{ type }.#{ base_suffix }"
51
+ defaults << :"#{ type }.#{ base_suffix }"
52
+
53
+ [root, defaults]
54
+ end
55
+ end
56
+ end
57
+
5
58
  class Translator
6
- def self.shortcut(meth_name, section)
7
- class_eval <<-RUBY
8
- def #{ meth_name }(key, options = {})
9
- I18n.t "\#{ ns }.#{ section }.\#{ key }",
10
- { default: :"#{ section }.\#{ key }" }.merge(options)
59
+ class << self
60
+ def lookup_key_method(meth_name, path)
61
+ class_eval <<-RUBY
62
+ def #{ meth_name }(key, options = {})
63
+ I18n.t "\#{ _config.fetch(:ns) }.#{ path }.\#{ key }",
64
+ { default: [:"#{ path }.\#{ key }"] }.merge(options)
65
+ end
66
+ RUBY
67
+ end
68
+
69
+ def settings(custom = nil)
70
+ @settings ||= {}
71
+
72
+ if custom
73
+ unknown = custom.keys.detect { |key| ![:downcase, :prefix].include?(key) }
74
+ if unknown
75
+ raise ArgumentError, "TT doesn't know `#{ unknown }` option in the configuration"
76
+ else
77
+ @settings.merge!(custom)
78
+ end
11
79
  end
12
- RUBY
80
+
81
+ @settings
82
+ end
13
83
  end
14
84
 
15
- def initialize(ns, section)
16
- @ns = ns
17
- @section = section
85
+ lookup_key_method :c, :common
86
+
87
+ def initialize(ns, section = nil)
88
+ @lookup = Utils.lookup(self.class.settings[:prefix])
89
+ @err_lookup = Utils.lookup(self.class.settings[:prefix], :messages)
90
+
91
+ ns = Utils.to_parts(ns).join('.')
92
+ @config = { ns: ns, root: (section ? "#{ ns }.#{ section }" : ns) }
93
+ default_model = ns.to_s.singularize
94
+ [:actions, :attributes, :enums, :models].each do |i|
95
+ @config[i] = @lookup.call(default_model, i)
96
+ end
97
+ @config[:errors] = @err_lookup.call(default_model, :errors)
98
+
99
+ @downcase = self.class.settings.fetch(:downcase, Utils::DOWNCASE)
18
100
  end
19
101
 
20
- def t(key, options = {})
21
- I18n.t "#{ ns }.#{ section }.#{ key }",
22
- { default: :"#{ ns }.common.#{ key }" }.merge(options)
102
+ def a(name, model_name = nil, custom = {})
103
+ path, defaults = _resolve(model_name, :actions, name)
104
+
105
+ resource = r(model_name)
106
+ resources = rs(model_name)
107
+ I18n.t path, {
108
+ default: defaults, r: @downcase.call(resource, I18n.locale), R: resource,
109
+ rs: @downcase.call(resources, I18n.locale), RS: resources
110
+ }.merge!(custom)
23
111
  end
24
112
 
25
- shortcut :c, :common
26
- shortcut :f, :form
113
+ def attr(name, model_name = nil)
114
+ path, defaults = _resolve(model_name, :attributes, name)
115
+ I18n.t path, default: defaults
116
+ end
27
117
 
28
- def attr(name, klass = context_klass)
29
- klass.human_attribute_name(name)
118
+ def enum(name, kind, model_name = nil)
119
+ path, defaults = _resolve(model_name, :enums, "#{ name }.#{ kind }")
120
+ I18n.t path, default: defaults
30
121
  end
31
122
 
32
- def enum(name, kind, klass = context_klass)
33
- klass.human_attribute_name("#{ name }_#{ kind }")
123
+ def e(attr_name, error_name, *args)
124
+ custom = args.last.is_a?(Hash) ? args.pop : {}
125
+ model_name = args.first
126
+ path, defaults = _resolve_errors(model_name, attr_name, error_name)
127
+ I18n.t path, { default: defaults }.merge!(custom)
34
128
  end
35
129
 
36
- def resource(klass = context_klass)
37
- klass.model_name.human(count: 1)
130
+ def r(model_name = nil)
131
+ rs(model_name, 1)
38
132
  end
39
- alias_method :record, :resource
40
133
 
41
- def resources(klass = context_klass)
42
- klass.model_name.human(count: 10)
134
+ def rs(model_name = nil, count = 10)
135
+ path, defaults = _resolve(model_name, :models)
136
+ I18n.t path, default: defaults, count: count
43
137
  end
44
- alias_method :records, :resources
45
138
 
46
- def no_resources(klass = context_klass)
47
- klass.model_name.human(count: 0)
139
+ def t(key, custom = {})
140
+ defaults = [:"#{ _config.fetch(:ns) }.common.#{ key }"].concat(Array(custom[:default]))
141
+ I18n.t "#{ _config.fetch(:root) }.#{ key }", custom.merge(default: defaults)
48
142
  end
49
- alias_method :no_records, :no_resources
50
143
 
51
144
  private
52
145
 
53
- attr_reader :ns, :section
146
+ def _config
147
+ @config
148
+ end
54
149
 
55
- def context_klass
56
- return @context_klass if @context_klass
150
+ def _resolve(model_name, type, key = nil)
151
+ _resolve_with_lookup(@lookup, model_name, type, key)
152
+ end
57
153
 
58
- @context_klass = ns.split('.').map(&:classify).join('::').singularize.constantize
154
+ def _resolve_errors(model_name, attr_name, error_name)
155
+ if attr_name == :base
156
+ _resolve_with_lookup(@err_lookup, model_name, :errors, error_name)
157
+ else
158
+ path, _defaults = _resolve(model_name, :errors, "#{ attr_name }.#{ error_name }")
159
+ defaults = _defaults + ["errors.messages.#{ error_name }".to_sym]
160
+ return path, defaults
161
+ end
162
+ end
163
+
164
+ def _resolve_with_lookup(lookup, model_name, type, key)
165
+ paths = model_name ? lookup.call(model_name, type) : _config.fetch(type)
166
+ if key
167
+ return "#{ paths.first }.#{ key }", paths.last.map { |i| :"#{ i }.#{ key }" }
168
+ else
169
+ return *paths
170
+ end
59
171
  end
60
172
 
61
173
  ActiveSupport.run_load_hooks(:tt, self)
62
174
  end
175
+
176
+ def self.fork(&block)
177
+ Class.new(Translator, &block)
178
+ end
179
+
180
+ def self.config(&block)
181
+ Translator.instance_exec(&block)
182
+ end
63
183
  end
64
184
 
65
185
  if defined?(ActionPack) || defined?(ActionMailer)
@@ -68,12 +188,13 @@ if defined?(ActionPack) || defined?(ActionMailer)
68
188
 
69
189
  included do
70
190
  helper_method :tt
191
+
192
+ prepend_before_filter { instance_variable_set(:@tt, ::TT::Translator.new(controller_path, action_name)) }
71
193
  end
72
194
 
73
195
  private
74
196
 
75
197
  def tt(*args)
76
- @tt ||= ::TT::Translator.new(controller_path.gsub('/', '.'), action_name)
77
198
  args.empty? ? @tt : @tt.t(*args)
78
199
  end
79
200
  end
@@ -86,3 +207,9 @@ if defined?(ActionPack) || defined?(ActionMailer)
86
207
  include ::TT::Helper
87
208
  end
88
209
  end
210
+
211
+ if defined?(ActiveRecord)
212
+ ActiveSupport.on_load(:active_record) do
213
+ TT.config(prefix: :activerecord)
214
+ end
215
+ end
@@ -0,0 +1,96 @@
1
+ # Dos-T
2
+
3
+ [![Build Status](https://travis-ci.org/jalkoby/tt.svg?branch=master)](https://travis-ci.org/jalkoby/tt)
4
+ [![Gem Version](https://badge.fury.io/rb/t_t.svg)](https://badge.fury.io/rb/t_t)
5
+
6
+ Dos-T introduces a translation convention for a ruby web application (with a focus on the rails flow). The library is based on the next ideas:
7
+ - focus on a every day issues
8
+ - reduce amount of duplications inside translation files
9
+ - easy to use from day one & minimum to write (nobody likes to write a long and obvious method names)
10
+ - have a clear defaults
11
+
12
+ ## Usage
13
+
14
+ Dos-T adds an extra helper method `tt` into your controllers, mailers & views. The best way to explain all features
15
+ is to look at [Cheatsheet](./cheatsheet.md). The below is shown a brief overview:
16
+
17
+ ```Haml
18
+ # en:
19
+ # actions:
20
+ # add:
21
+ # base: "Add a new %{r}"
22
+ # attributes:
23
+ # user:
24
+ # name: "Name"
25
+ # email: "Email"
26
+ # role: "Role"
27
+ # common:
28
+ # actions: "Actions"
29
+ # confirm: "Are you sure?"
30
+ # edit: "Edit"
31
+ # delete: "Delete"
32
+ # enums:
33
+ # user:
34
+ # role:
35
+ # a: "Admin"
36
+ # g: "Guest"
37
+ # m: "Manager"
38
+ # models:
39
+ # user:
40
+ # one: "User"
41
+ # other: "Users"
42
+
43
+ # app/views/users/index.haml
44
+ %h2= tt.rs :user
45
+
46
+ %table
47
+ %thead
48
+ %th= tt.attr :name
49
+ %th= tt.attr :email
50
+ %th= tt.attr :role
51
+ %th= tt.c :actions
52
+
53
+ %tbody
54
+ - @users.each do |user|
55
+ %tr
56
+ %td= user.name
57
+ %td= user.email
58
+ %td= tt.enum :role, user.role
59
+ %td
60
+ = link_to tt.c(:edit), edit_user_path(user)
61
+ = link_to tt.c(:delete), user_path(user), method: :delete, confirm: tt.c(:confirm)
62
+
63
+ = link_to tt.a(:add), new_user_path
64
+ ```
65
+
66
+ The result will be the next:
67
+ ```Haml
68
+ %h2 Users
69
+
70
+ %table
71
+ %thead
72
+ %th Name
73
+ %th Email
74
+ %th Role
75
+ %th Actions
76
+
77
+ %tbody
78
+ - @users.each do |user|
79
+ %tr
80
+ %td= user.name
81
+ %td= user.email
82
+ %td= { 'a' => 'Admin', 'g' => 'Guest', 'm' => 'Manager' }[user.role]
83
+ %td
84
+ = link_to 'Edit', edit_user_path(user)
85
+ = link_to 'Delete', user_path(user), method: :delete, confirm: 'Are you sure?'
86
+
87
+ = link_to 'Add a new user', new_user_path
88
+ ```
89
+
90
+ ## Setup
91
+
92
+ Just add `gem "t_t"` into your Gemfile and run `bundle`.
93
+
94
+ ## Requirements
95
+
96
+ Dos-T is tested against Ruby 1.9.3+. If your application uses Ruby on Rails the framework version should be 3.2+
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "t_t"
5
- spec.version = "0.0.1"
5
+ spec.version = "1.0.0"
6
6
  spec.authors = ["Sergey Pchelintsev"]
7
7
  spec.email = ["mail@sergeyp.me"]
8
8
  spec.summary = %q{An opinioned I18n helper}
@@ -7,6 +7,7 @@ end
7
7
  describe "ActionPack integration" do
8
8
  before do
9
9
  @controller = TTController.new
10
+ @controller.run_callbacks(:process_action)
10
11
  end
11
12
 
12
13
  it 'returns tt instance if the method was called without args' do
@@ -14,6 +15,7 @@ describe "ActionPack integration" do
14
15
  end
15
16
 
16
17
  it 'calls #t if args were passed' do
18
+ load_i18n(common: { tar: 'global_tar' })
17
19
  assert_equal @controller.tt.c(:tar), 'global_tar'
18
20
  end
19
21
  end
@@ -0,0 +1,162 @@
1
+ require 'test_helper'
2
+
3
+ describe 'Methods related to models' do
4
+ before do
5
+ @tt = ARTranslator.new("admin/users", "spec")
6
+ end
7
+
8
+ describe 'actions' do
9
+ before do
10
+ load_i18n({
11
+ actions: {
12
+ base: { do: 'Do', make: 'Do', execute: 'Do' },
13
+ user: {
14
+ make: 'Make', execute: 'Make',
15
+ subscribe: 'The %{r} will be subscribed with other %{rs} of this day. %{RS} get 10% off with the subscription.'
16
+ },
17
+ admin: { user: { execute: 'Execute' } }
18
+ },
19
+ models: { admin: { user: { one: "Admin", other: "Admins" } } }
20
+ })
21
+ end
22
+
23
+ it 'returns a specific action' do
24
+ assert_equal @tt.a(:execute), 'Execute'
25
+ end
26
+
27
+ it 'returns a pure model action' do
28
+ assert_equal @tt.a(:make), 'Make'
29
+ end
30
+
31
+ it 'returns a base action' do
32
+ assert_equal @tt.a(:do), 'Do'
33
+ end
34
+
35
+ it 'allows to specify a custom model' do
36
+ assert_equal @tt.a(:execute, :user), 'Make'
37
+ end
38
+
39
+ it 'passes translations of a model' do
40
+ assert_equal @tt.a(:subscribe), 'The admin will be subscribed with other admins of this day. Admins get 10% off with the subscription.'
41
+ end
42
+ end
43
+
44
+ describe 'attributes' do
45
+ before do
46
+ load_i18n(attributes: {
47
+ base: { name: 'Name', phone: 'Phone', email: 'Email' },
48
+ user: { name: 'Nick', phone: 'Notification phone' },
49
+ admin: { user: { name: 'Contact admin name' } }
50
+ })
51
+ end
52
+
53
+ it 'returns a specific attribute' do
54
+ assert_equal @tt.attr(:name), 'Contact admin name'
55
+ end
56
+
57
+ it 'returns a pure model attribute' do
58
+ assert_equal @tt.attr(:phone), 'Notification phone'
59
+ end
60
+
61
+ it 'returns a base attribute' do
62
+ assert_equal @tt.attr(:email), 'Email'
63
+ end
64
+
65
+ it 'allows to specify a custom model' do
66
+ assert_equal @tt.attr(:name, :user), 'Nick'
67
+ end
68
+ end
69
+
70
+ describe 'enums' do
71
+ before do
72
+ load_i18n(enums: {
73
+ base: { gender: { f: 'Female', m: 'Male', o: 'Other' } },
74
+ user: { gender: { f: 'Woman', m: 'Man' } },
75
+ admin: { user: { gender: { f: 'Admin' } } }
76
+ })
77
+ end
78
+
79
+ it 'returns a specific enum' do
80
+ assert_equal @tt.enum(:gender, :f), 'Admin'
81
+ end
82
+
83
+ it 'returns a pure model enum' do
84
+ assert_equal @tt.enum(:gender, :m), 'Man'
85
+ end
86
+
87
+ it 'returns a base enum' do
88
+ assert_equal @tt.enum(:gender, :o), 'Other'
89
+ end
90
+
91
+ it 'allows to specify a custom model' do
92
+ assert_equal @tt.enum(:gender, :f, :user), 'Woman'
93
+ end
94
+ end
95
+
96
+ describe 'errors' do
97
+ before do
98
+ load_i18n(errors: {
99
+ messages: { name: { blank: "should be filled" }, fields_missed: "not all required fields are filled" },
100
+ user: { password: { weak: "Your password is weak" }, limit: 'The limit has been reached', duplicated: "The site has an account with the inputed information" },
101
+ admin: { user: { email: { empty: "The admin email should be filled" }, limit: "The system has reached the admin limit" } }
102
+ })
103
+ end
104
+
105
+ it 'returns a specific error' do
106
+ assert_equal @tt.e(:email, :empty), 'The admin email should be filled'
107
+ end
108
+
109
+ it 'returns a specific base error' do
110
+ assert_equal @tt.e(:base, :limit), 'The system has reached the admin limit'
111
+ end
112
+
113
+ it 'returns a pure model error' do
114
+ assert_equal @tt.e(:password, :weak), 'Your password is weak'
115
+ end
116
+
117
+ it 'returns a base pure model error' do
118
+ assert_equal @tt.e(:base, :duplicated), 'The site has an account with the inputed information'
119
+ end
120
+
121
+ it 'returns a base attribute error' do
122
+ assert_equal @tt.e(:name, :blank), 'should be filled'
123
+ end
124
+
125
+ it 'returns a base error' do
126
+ assert_equal @tt.e(:base, :fields_missed), 'not all required fields are filled'
127
+ assert_equal @tt.e(:roo, :fields_missed), 'not all required fields are filled'
128
+ end
129
+
130
+ it 'allows to specify a custom model' do
131
+ assert_equal @tt.e(:base, :limit, :user), 'The limit has been reached'
132
+ end
133
+ end
134
+
135
+ describe 'resource names' do
136
+ before do
137
+ @tt = ARTranslator.new('public/people')
138
+ load_i18n({
139
+ models: { person: { one: "whatever", other: "whatever" }, user: { one: "User", other: "Users" } },
140
+ activerecord: { models: {
141
+ public: { person: { one: "Celebrity", other: "Celebrities" } },
142
+ person: { one: "Person", other: "People" }
143
+ } }
144
+ })
145
+ end
146
+
147
+ it 'handles namespaces' do
148
+ assert_equal @tt.r, 'Celebrity'
149
+ assert_equal @tt.rs, 'Celebrities'
150
+ end
151
+
152
+ it 'looks inside orm namespace' do
153
+ assert_equal @tt.r(:person), 'Person'
154
+ assert_equal @tt.rs(:person), 'People'
155
+ end
156
+
157
+ it "fallbacks into base if orm namespace doesn't have a key" do
158
+ assert_equal @tt.r(:user), 'User'
159
+ assert_equal @tt.rs(:user), 'Users'
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,70 @@
1
+ require 'test_helper'
2
+
3
+ describe 'methods related to views' do
4
+ before do
5
+ @tt = ViewTranslator.new("tt", "spec")
6
+ end
7
+
8
+ describe '#t' do
9
+ before do
10
+ load_i18n(tt: {
11
+ common: { too: "namespace_too" },
12
+ spec: { foo: "spec_foo" }
13
+ })
14
+ end
15
+
16
+ it "looks for a section translation first" do
17
+ assert_equal @tt.t(:foo), "spec_foo"
18
+ end
19
+
20
+ it "looks into the section commons" do
21
+ assert_equal @tt.t(:too), "namespace_too"
22
+ end
23
+
24
+ it "allows a custom options" do
25
+ assert_equal @tt.t(:tar, default: "default_tar"), "default_tar"
26
+ end
27
+ end
28
+
29
+ describe '#c' do
30
+ before do
31
+ load_i18n(
32
+ common: { tar: 'global_tar' },
33
+ tt: { common: { foo: "namespace_foo" }, }
34
+ )
35
+ end
36
+
37
+ it "looks for a namespace translation first" do
38
+ assert_equal @tt.c(:foo), "namespace_foo"
39
+ end
40
+
41
+ it "falls back to a global translation" do
42
+ assert_equal @tt.c(:tar), "global_tar"
43
+ end
44
+
45
+ it "allows a custom options" do
46
+ assert_equal @tt.c(:car, default: "default_car"), 'default_car'
47
+ end
48
+ end
49
+
50
+ describe '#f' do
51
+ before do
52
+ load_i18n(
53
+ form: { edit: "global_edit", save: "global_save" },
54
+ tt: { form: { edit: "namespace_edit" } }
55
+ )
56
+ end
57
+
58
+ it "looks for a namespace translation first" do
59
+ assert_equal @tt.f(:edit), "namespace_edit"
60
+ end
61
+
62
+ it "falls back to a global translation" do
63
+ assert_equal @tt.f(:save), "global_save"
64
+ end
65
+
66
+ it "allows a custom options" do
67
+ assert_equal @tt.f(:commit, default: "default_commit"), "default_commit"
68
+ end
69
+ end
70
+ end
@@ -4,39 +4,22 @@ require "rack/test"
4
4
  require "action_controller"
5
5
  require "t_t"
6
6
 
7
+ ViewTranslator = TT.fork do
8
+ lookup_key_method :f, :form
9
+ end
10
+
11
+ ARTranslator = TT.fork do
12
+ settings prefix: :activerecord
13
+ end
14
+
7
15
  I18n.backend = I18n::Backend::Simple.new
8
- I18n.backend.store_translations(:en, {
9
- common: {
10
- tar: 'global_tar'
11
- },
12
- crumbs: {
13
- index: 'global_index',
14
- new: 'global_new'
15
- },
16
- form: {
17
- edit: "global_edit",
18
- save: "global_save"
19
- },
20
- tooltip: {
21
- info: "global_info",
22
- notice: "global_notice"
23
- },
24
- tt: {
25
- common: {
26
- foo: "namespace_foo",
27
- bar: "namespace_bar"
28
- },
29
- crumbs: {
30
- new: 'namespace_new'
31
- },
32
- form: {
33
- edit: "namespace_edit"
34
- },
35
- spec: {
36
- foo: "spec_foo"
37
- },
38
- tooltip: {
39
- info: "namespace_info"
40
- }
41
- }
42
- })
16
+
17
+ class Minitest::Spec
18
+ after :each do
19
+ I18n.backend.reload!
20
+ end
21
+
22
+ def load_i18n(data)
23
+ I18n.backend.store_translations(:en, data)
24
+ end
25
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: t_t
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergey Pchelintsev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-31 00:00:00.000000000 Z
11
+ date: 2016-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -116,14 +116,22 @@ extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
118
  - ".gitignore"
119
+ - ".travis.yml"
119
120
  - Gemfile
120
- - LICENSE.txt
121
- - README.md
122
121
  - Rakefile
122
+ - cheatsheet.md
123
+ - examples/simple_app.yml
124
+ - gemfiles/Gemfile.actionpack-3.1.x
125
+ - gemfiles/Gemfile.actionpack-3.2.x
126
+ - gemfiles/Gemfile.actionpack-4.0.x
127
+ - gemfiles/Gemfile.actionpack-4.1.x
128
+ - gemfiles/Gemfile.actionpack-4.2.x
123
129
  - lib/t_t.rb
130
+ - readme.md
124
131
  - t_t.gemspec
125
132
  - tests/lib/action_pack_test.rb
126
- - tests/lib/t_t_test.rb
133
+ - tests/lib/model_test.rb
134
+ - tests/lib/view_test.rb
127
135
  - tests/test_helper.rb
128
136
  homepage: ''
129
137
  licenses:
@@ -145,8 +153,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
153
  version: '0'
146
154
  requirements: []
147
155
  rubyforge_project:
148
- rubygems_version: 2.2.2
156
+ rubygems_version: 2.4.5
149
157
  signing_key:
150
158
  specification_version: 4
151
159
  summary: An opinioned I18n helper
152
160
  test_files: []
161
+ has_rdoc:
@@ -1,22 +0,0 @@
1
- Copyright (c) 2015 Sergey Pchelintsev
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md DELETED
@@ -1,91 +0,0 @@
1
- ## About
2
-
3
- The main goal of Dos-T is reducing time on supporting a multi-language web application by providing a few conventions and a short method names. We believe that it's a primary reason which slows down development. Cause it's boring to write a long path like `t('namespace.controller_name.action_name.section.key')`. Let's better spend time on something more interesting.
4
-
5
- So what's makes Dos-T such a good tool(on our opinion):
6
-
7
- ### Example of page
8
-
9
- ```haml
10
- / users#index
11
- = link_to tt.c(:new_resource, model: tt.resource), new_user_path, "data-tooltip" => tt(:new_user_tip)
12
-
13
- %table
14
- %tr
15
- %th= tt.attr :name
16
- %th= tt.attr :email
17
- %th= tt.attr :phone
18
- %th= tt.attr :role
19
- %th= tt.c :actions
20
- - @users.each do |user|
21
- %tr
22
- %td= user.name
23
- %td= user.email
24
- %td= user.phone
25
- %td= tt.enum :role, user.role
26
- %td
27
- = link_to tt.f(:edit), edit_user_path(user)
28
- = link_to tt.f(:delete), user_path(user), method: :delete, confirm: tt.c(:confirm)
29
-
30
- / tt.c looks in 'users.common', 'common'
31
- / tt.f looks in 'users.form', 'form'
32
- / tt looks in 'users.index', 'users.common'
33
- / tt.attr - calls human_attribute_name on User
34
- / tt.enum - calls human_attribute_name on User with role_%value%
35
- / tt.resource - User.model_name.human(count: 1)
36
- ```
37
-
38
- ### Global commons
39
-
40
- `tt.c` - in every application there are some elements which are present in every page. For example, if a page has "delete some resource" button/link, it's good to have a confirmation message which tells a user "Are you sure?". At this point you add a key for this page, for example, in "admin.users.index.confirm" path and on page call `t('.confirm')`. Rails is smart enough to prepend a full path to ".confirm" key. But then you need to add confirmation on `admin/users#show` and you, probably, will not duplicate it for "show" page and move it into a common section. After that the translation helper can't help us and we need to provide a full path – `t('common.confirm')`. We reduce a duplication of translation keys, but have to write a long methods. Well, as always, programming is a compromise. But not this time, with Dos-T you can have both – just call `tt.c(:confirm)`. At first it will look into a section's common node(description of a section see below). If Dos-T doesn't find a translation there it will look into the global *common* >>> *common.confirm*. You, probably, are interested what's a section. By a section Dos-T means I18n path of the current controller(mailer). Let's review the previous example. If our current controller is `Admin::UsersController`, the section is *admin.users*. That's why if we want for deleting users a special confirmation we just add "admin.users.common.confirmation" key and it's done.
41
-
42
- `tt.f` - the global `common` section could fast become a huge and you will add some namespaces into it. We prefer a facts over a supposes, but there is a 100% assumption that you will have this subsection - `common.form` with `save`, `edit`, `delete` and etc. Cause we don't know any application which doesn't have that. That's why Dos-T has another method `tt.f` which like `tt.c` - first looks into the current section(*controller_path.form*) and fallbacks into the global("form").
43
-
44
- And finally, Dos-T allows you to define a new "common-used" sections. For example, for breadcrumbs. Just place "tt.rb" file in config/initializations that:
45
-
46
- ```ruby
47
- ActiveSupport.on_load(:tt) do
48
- shortcut(:crumbs, :breadcrumbs) # => tt.crumbs(:index) which looks into `breadcrumbs` sections
49
- shortcut(:tip, :tooltips) # => tt.tip(:readonly) which looks into `tooltips` sections
50
- end
51
- ```
52
-
53
- ### Section's commons
54
-
55
- `tt` - let's back to our example with user management pages. Our clients decided to add a gravatar support. To make this feature more clear to admins we should put a tooltip with a description on index and show page, next to label "Gravatar". It brings a problem where to put a translation. If we put it into 'admin.users.index' we can use `t('.gravatar')` on index page, but have to use `t('admin.users.index.gravatar')` on show page and vice versa. And there Dos-T helps us. Just put `tt(:gravatar)` and put the tip into 'admin.users.common'. First it will act like a `t('.gravatar')` and fallbacks into section's common. And yes, `tt(:key)` is one symbol shorter than t('.key') – you can't avoid `t` in a favour to `tt`.
56
-
57
- ### Resource translations
58
-
59
- `tt.attr` - we think every developer enjoys how `form_for` easily translates column's label - `f.label :column_name` - and Rails will magically translate it. But then we have to use an ugly way(`User.human_attribute_name(:column_name)`) to reuse these translations on index and show pages. It's become boring to type again and again this `human_attribute_name`. Dos-T provides a shortcut `tt.attr :column_name, User`. But it could be a shorter, cause if you call it in `UsersController` in 9/10 you closely work with User model. That's why, a second argument in `#attr` method is an optional and default value is a context class. A context class is computed on a controller name. If it's `users_controller`, Dos-T expects for a User model presence. If it's `Admin::UsersController` a context class is still User model.
60
-
61
- ### Other useful methods
62
-
63
- * `tt.record([context_class])` – returns the singular human name of a model class(alias - resource)
64
- * `tt.records([context_class])` – returns the plural human name of a model class(alias – resources)
65
- * `tt.no_records([context_class])` – returns the zero form human name of a model class(alias – no_resources)
66
- * `tt.enum(attr_name, variant, [context_class])` – returns a human variant name of an attribute. It looks for human attribute name of "%attr_name%_%variant%"
67
-
68
- ## Installation
69
-
70
- Add this line to your application's Gemfile:
71
-
72
- ```ruby
73
- gem 't_t'
74
- ```
75
-
76
- And then execute:
77
-
78
- $ bundle
79
-
80
- Or install it yourself as:
81
-
82
- $ gem install t_t
83
-
84
-
85
- ## Contributing
86
-
87
- 1. Fork it ( https://github.com/jalkoby/t_t/fork )
88
- 2. Create your feature branch (`git checkout -b my-new-feature`)
89
- 3. Commit your changes (`git commit -am 'Add some feature'`)
90
- 4. Push to the branch (`git push origin my-new-feature`)
91
- 5. Create a new Pull Request
@@ -1,146 +0,0 @@
1
- require 'test_helper'
2
-
3
- describe TT::Translator do
4
- before do
5
- @tt = TT::Translator.new("tt", "spec")
6
- end
7
-
8
- describe '#t' do
9
- it "looks for a section translation first" do
10
- assert_equal @tt.t(:foo), "spec_foo"
11
- end
12
-
13
- it "falls back to common namespace translations" do
14
- assert_equal @tt.t(:bar), "namespace_bar"
15
- end
16
-
17
- it "allows a custom options" do
18
- assert_equal @tt.t(:tar, default: "default_tar"), "default_tar"
19
- end
20
- end
21
-
22
- describe '#c' do
23
- it "looks for a namespace translation first" do
24
- assert_equal @tt.c(:foo), "namespace_foo"
25
- end
26
-
27
- it "falls back to a global translation" do
28
- assert_equal @tt.c(:tar), "global_tar"
29
- end
30
-
31
- it "allows a custom options" do
32
- assert_equal @tt.c(:car, default: "default_car"), 'default_car'
33
- end
34
- end
35
-
36
- describe '#f' do
37
- it "looks for a namespace translation first" do
38
- assert_equal @tt.f(:edit), "namespace_edit"
39
- end
40
-
41
- it "falls back to a global translation" do
42
- assert_equal @tt.f(:save), "global_save"
43
- end
44
-
45
- it "allows a custom options" do
46
- assert_equal @tt.f(:commit, default: "default_commit"), "default_commit"
47
- end
48
- end
49
-
50
- describe 'a model related methods' do
51
- before do
52
- @klass = Minitest::Mock.new
53
- end
54
-
55
- describe '#attr' do
56
- it 'uses the provided class' do
57
- @klass.expect(:human_attribute_name, 'Nombre', [:name])
58
- assert_equal @tt.attr(:name, @klass), 'Nombre'
59
- end
60
-
61
- it 'uses a context class by default' do
62
- @klass.expect(:human_attribute_name, 'Nombre', [:name])
63
- @tt.stub(:context_klass, @klass) do
64
- assert_equal @tt.attr(:name), 'Nombre'
65
- end
66
- end
67
- end
68
-
69
- describe '#enum' do
70
- it 'uses the provided class' do
71
- @klass.expect(:human_attribute_name, 'Melody', ['type_melody'])
72
- assert_equal @tt.enum(:type, :melody, @klass), 'Melody'
73
- end
74
-
75
- it 'uses a context class by default' do
76
- @klass.expect(:human_attribute_name, 'Sound', ['type_sound'])
77
- @tt.stub(:context_klass, @klass) do
78
- assert_equal @tt.enum(:type, :sound), 'Sound'
79
- end
80
- end
81
- end
82
-
83
- describe 'a model name' do
84
- before do
85
- @model_name = Minitest::Mock.new
86
- @klass.expect(:model_name, @model_name)
87
- end
88
-
89
- describe '#resource' do
90
- before do
91
- @model_name.expect(:human, 'Coche', [{ count: 1 }])
92
- end
93
-
94
- it 'uses the provided class' do
95
- assert_equal @tt.resource(@klass), 'Coche'
96
- end
97
-
98
- it 'uses a context class by default' do
99
- @tt.stub(:context_klass, @klass) do
100
- assert_equal @tt.resource, 'Coche'
101
- end
102
- end
103
- end
104
-
105
- describe '#resources' do
106
- before do
107
- @model_name.expect(:human, 'Coches', [{ count: 10 }])
108
- end
109
-
110
- it 'uses the provided class' do
111
- assert_equal @tt.resources(@klass), 'Coches'
112
- end
113
-
114
- it 'uses a context class by default' do
115
- @tt.stub(:context_klass, @klass) do
116
- assert_equal @tt.resources, 'Coches'
117
- end
118
- end
119
- end
120
-
121
- describe '#no_resources' do
122
- before do
123
- @model_name.expect(:human, 'Coches', [{ count: 0 }])
124
- end
125
-
126
- it 'uses the provided class' do
127
- assert_equal @tt.no_resources(@klass), 'Coches'
128
- end
129
-
130
- it 'uses a context class by default' do
131
- @tt.stub(:context_klass, @klass) do
132
- assert_equal @tt.no_resources, 'Coches'
133
- end
134
- end
135
- end
136
-
137
- after do
138
- assert @model_name.verify
139
- end
140
- end
141
-
142
- after do
143
- assert @klass.verify
144
- end
145
- end
146
- end