t_t 0.0.1 → 1.0.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.
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