mongo_translatable 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. data/.document +5 -0
  2. data/.gitignore +26 -0
  3. data/.gitmodules +3 -0
  4. data/LICENSE +295 -0
  5. data/README.rdoc +131 -0
  6. data/Rakefile +55 -0
  7. data/VERSION +1 -0
  8. data/app/controllers/translations_controller.rb +150 -0
  9. data/app/helpers/translations_helper.rb +71 -0
  10. data/app/views/layouts/translations.html.erb +18 -0
  11. data/app/views/translations/_form.html.erb +50 -0
  12. data/app/views/translations/_translatable_value.html.erb +17 -0
  13. data/app/views/translations/_translation_field.html.erb +34 -0
  14. data/app/views/translations/_translation_field_input.html.erb +8 -0
  15. data/app/views/translations/edit.html.erb +8 -0
  16. data/app/views/translations/index.html.erb +22 -0
  17. data/app/views/translations/new.html.erb +7 -0
  18. data/app/views/translations/show.html.erb +12 -0
  19. data/config/locales/en.yml +33 -0
  20. data/config/locales/fr.yml +18 -0
  21. data/lib/mongo_translatable.rb +336 -0
  22. data/lib/mongo_translatable_configuration.rb +5 -0
  23. data/lib/translatables_helper.rb +227 -0
  24. data/lib/translations_controller_helpers.rb +37 -0
  25. data/rails/init.rb +3 -0
  26. data/test/full_2_3_5_app_with_tests/.gitignore +27 -0
  27. data/test/full_2_3_5_app_with_tests/README +1 -0
  28. data/test/full_2_3_5_app_with_tests/Rakefile +10 -0
  29. data/test/full_2_3_5_app_with_tests/app/controllers/application_controller.rb +26 -0
  30. data/test/full_2_3_5_app_with_tests/app/controllers/items_controller.rb +85 -0
  31. data/test/full_2_3_5_app_with_tests/app/helpers/application_helper.rb +3 -0
  32. data/test/full_2_3_5_app_with_tests/app/helpers/items_helper.rb +2 -0
  33. data/test/full_2_3_5_app_with_tests/app/models/comment.rb +3 -0
  34. data/test/full_2_3_5_app_with_tests/app/models/item.rb +5 -0
  35. data/test/full_2_3_5_app_with_tests/app/models/not_swapped_in_record.rb +3 -0
  36. data/test/full_2_3_5_app_with_tests/app/models/person.rb +3 -0
  37. data/test/full_2_3_5_app_with_tests/app/models/recipe.rb +21 -0
  38. data/test/full_2_3_5_app_with_tests/app/views/items/edit.html.erb +24 -0
  39. data/test/full_2_3_5_app_with_tests/app/views/items/index.html.erb +24 -0
  40. data/test/full_2_3_5_app_with_tests/app/views/items/new.html.erb +23 -0
  41. data/test/full_2_3_5_app_with_tests/app/views/items/show.html.erb +21 -0
  42. data/test/full_2_3_5_app_with_tests/app/views/layouts/items.html.erb +19 -0
  43. data/test/full_2_3_5_app_with_tests/config/boot.rb +110 -0
  44. data/test/full_2_3_5_app_with_tests/config/database.yml +22 -0
  45. data/test/full_2_3_5_app_with_tests/config/environment.rb +54 -0
  46. data/test/full_2_3_5_app_with_tests/config/environments/development.rb +17 -0
  47. data/test/full_2_3_5_app_with_tests/config/environments/production.rb +28 -0
  48. data/test/full_2_3_5_app_with_tests/config/environments/test.rb +28 -0
  49. data/test/full_2_3_5_app_with_tests/config/initializers/backtrace_silencers.rb +7 -0
  50. data/test/full_2_3_5_app_with_tests/config/initializers/inflections.rb +10 -0
  51. data/test/full_2_3_5_app_with_tests/config/initializers/mime_types.rb +5 -0
  52. data/test/full_2_3_5_app_with_tests/config/initializers/new_rails_defaults.rb +21 -0
  53. data/test/full_2_3_5_app_with_tests/config/initializers/session_store.rb +15 -0
  54. data/test/full_2_3_5_app_with_tests/config/locales.yml +5 -0
  55. data/test/full_2_3_5_app_with_tests/config/locales/en.yml +4 -0
  56. data/test/full_2_3_5_app_with_tests/config/locales/fr.yml +4 -0
  57. data/test/full_2_3_5_app_with_tests/config/locales/zh.yml +4 -0
  58. data/test/full_2_3_5_app_with_tests/config/routes.rb +4 -0
  59. data/test/full_2_3_5_app_with_tests/db/migrate/20100407010602_create_items.rb +14 -0
  60. data/test/full_2_3_5_app_with_tests/db/migrate/20100504234216_create_not_swapped_in_records.rb +15 -0
  61. data/test/full_2_3_5_app_with_tests/db/migrate/20100509011052_create_people.rb +13 -0
  62. data/test/full_2_3_5_app_with_tests/db/migrate/20100509042718_create_comments.rb +14 -0
  63. data/test/full_2_3_5_app_with_tests/db/migrate/20110112023516_create_recipes.rb +14 -0
  64. data/test/full_2_3_5_app_with_tests/db/schema.rb +56 -0
  65. data/test/full_2_3_5_app_with_tests/db/seeds.rb +7 -0
  66. data/test/full_2_3_5_app_with_tests/doc/README_FOR_APP +2 -0
  67. data/test/full_2_3_5_app_with_tests/public/404.html +30 -0
  68. data/test/full_2_3_5_app_with_tests/public/422.html +30 -0
  69. data/test/full_2_3_5_app_with_tests/public/500.html +30 -0
  70. data/test/full_2_3_5_app_with_tests/public/favicon.ico +0 -0
  71. data/test/full_2_3_5_app_with_tests/public/images/rails.png +0 -0
  72. data/test/full_2_3_5_app_with_tests/public/index.html +275 -0
  73. data/test/full_2_3_5_app_with_tests/public/javascripts/application.js +2 -0
  74. data/test/full_2_3_5_app_with_tests/public/javascripts/controls.js +963 -0
  75. data/test/full_2_3_5_app_with_tests/public/javascripts/dragdrop.js +973 -0
  76. data/test/full_2_3_5_app_with_tests/public/javascripts/effects.js +1128 -0
  77. data/test/full_2_3_5_app_with_tests/public/javascripts/prototype.js +4320 -0
  78. data/test/full_2_3_5_app_with_tests/public/robots.txt +5 -0
  79. data/test/full_2_3_5_app_with_tests/public/stylesheets/scaffold.css +54 -0
  80. data/test/full_2_3_5_app_with_tests/script/about +4 -0
  81. data/test/full_2_3_5_app_with_tests/script/console +3 -0
  82. data/test/full_2_3_5_app_with_tests/script/dbconsole +3 -0
  83. data/test/full_2_3_5_app_with_tests/script/destroy +3 -0
  84. data/test/full_2_3_5_app_with_tests/script/generate +3 -0
  85. data/test/full_2_3_5_app_with_tests/script/performance/benchmarker +3 -0
  86. data/test/full_2_3_5_app_with_tests/script/performance/profiler +3 -0
  87. data/test/full_2_3_5_app_with_tests/script/plugin +3 -0
  88. data/test/full_2_3_5_app_with_tests/script/runner +3 -0
  89. data/test/full_2_3_5_app_with_tests/script/server +3 -0
  90. data/test/full_2_3_5_app_with_tests/test/factories.rb +18 -0
  91. data/test/full_2_3_5_app_with_tests/test/functional/translations_controller_test.rb +66 -0
  92. data/test/full_2_3_5_app_with_tests/test/integration/translation_test.rb +72 -0
  93. data/test/full_2_3_5_app_with_tests/test/performance/browsing_test.rb +9 -0
  94. data/test/full_2_3_5_app_with_tests/test/selenium.rb +83 -0
  95. data/test/full_2_3_5_app_with_tests/test/test_helper.rb +86 -0
  96. data/test/full_2_3_5_app_with_tests/test/unit/helpers/translatables_helper_test.rb +37 -0
  97. data/test/full_2_3_5_app_with_tests/test/unit/helpers/translations_helper_test.rb +62 -0
  98. data/test/full_2_3_5_app_with_tests/test/unit/mongo_translatable_test.rb +342 -0
  99. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/init.rb +1 -0
  100. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter.rb +94 -0
  101. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/base.rb +31 -0
  102. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/force_extension.rb +57 -0
  103. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/locale.rb +70 -0
  104. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/pagination.rb +33 -0
  105. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/uuid_token.rb +78 -0
  106. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/force_extension_spec.rb +65 -0
  107. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/generation_spec.rb +367 -0
  108. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/pagination_extension_spec.rb +19 -0
  109. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/recognition_spec.rb +76 -0
  110. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/routing_filter_spec.rb +114 -0
  111. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/spec_helper.rb +108 -0
  112. metadata +309 -0
@@ -0,0 +1,37 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'test_helper'
3
+
4
+ class TranslatablesHelperTest < ActionView::TestCase
5
+ context "Helpers for translatables" do
6
+ setup do
7
+ I18n.locale = I18n.default_locale
8
+ @item = Factory.create(:item, :label => "a label")
9
+ @translatable_params_name = "item"
10
+
11
+ def url_for_translated(options = { })
12
+ @controller.url_for_translated(options.merge(
13
+ :translated => @item,
14
+ :translatable_params_name => @translatable_params_name
15
+ ))
16
+ end
17
+ end
18
+
19
+ # TODO: current request need to be in environment for this to run
20
+ should "have provide available_in_locales_for that returns current translations for passed in item as list" do
21
+ @item.translate(:label => 'une étiquette', :locale => 'fr').save
22
+ html = "<ul><li><a href=\"/fr/items/1\">Français</li></ul>"
23
+ assert_equal html, available_in_locales_for(@item)
24
+ end
25
+
26
+ should "have provide needed_in_locales_for that returns current locales that don't have a translation for passed in item as list" do
27
+ locales = LOCALE_LABELS.keys - [:zh, :en]
28
+ translate_item_for_locales(@item, locales)
29
+ html = "<ul style='list-style:none; margin:0; padding:0;'>"
30
+ html += "<li style='float:left;'>Needs translating to:</li>"
31
+ html += "<li style=\"float: left; padding: 0 10px; \"><a href=\"/en/items/1/translations/new?to_locale=zh\">中文</a></li>"
32
+ html += "</ul><div style='clear:both;'></div>"
33
+ I18n.locale = I18n.default_locale
34
+ assert_equal html, needed_in_locales_for(@item)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,62 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'test_helper'
3
+
4
+ class TranslationsHelperTest < ActionView::TestCase
5
+ context "Helpers for translation" do
6
+ setup do
7
+ I18n.locale = I18n.default_locale
8
+ @translatable = Factory.create(:item, :label => "a label")
9
+ @translatable_class = Item
10
+ @translatable_key = :item_id
11
+ @translatable_params_name = "item"
12
+
13
+ def url_for_translated(options = { })
14
+ @controller.url_for_translated(options.merge(
15
+ :translated => @translatable,
16
+ :translatable_params_name => @translatable_params_name
17
+ ))
18
+ end
19
+ end
20
+
21
+ should "have avalailable_locales_for_options" do
22
+ locale_options = [["Français", "fr"],
23
+ ["中文", "zh"],
24
+ ["Suomi", "fi"],
25
+ ["العربية", "ar"],
26
+ ["English", "en"]]
27
+ assert_equal locale_options, available_locales_for_options
28
+ end
29
+
30
+ should "have provide available_in_locales that returns current translations for @translatable as list" do
31
+ @translatable.translate(:label => 'une étiquette', :locale => 'fr').save
32
+ html = "<ul><li><a href=\"http://test.host/en/items/1\">English</a></li><li><a href=\"http://test.host/fr/items/1\">Français</a></li></ul>"
33
+ assert_equal html, available_in_locales
34
+ end
35
+
36
+ should "have provide needed_in_locales that returns current locales that don't have a translation for @translatable as list" do
37
+ locales = LOCALE_LABELS.keys - [:zh, :en]
38
+ translate_item_for_locales(@translatable, locales)
39
+ html = "<ul><li><a href=\"/en/items/1/translations/new?to_locale=zh\">中文</a></li></ul>"
40
+ I18n.locale = I18n.default_locale
41
+ assert_equal html, needed_in_locales
42
+ end
43
+
44
+ should "take attribute_key and give localized label" do
45
+ assert_equal "Label", localized_label_for(:label)
46
+ end
47
+
48
+ should "take translatable and output internationalized html to display the original text of the attributes" do
49
+ array_with_hashes_of_translatable_attributes_with_internationalized_names = [{:attribute_key=>:label, :localized_label => "Label", :value => "a label"}]
50
+ # ignoring description for now (thus wrapped in array and .first)
51
+ assert_equal array_with_hashes_of_translatable_attributes_with_internationalized_names, [untranslated_values_with_localized_labels.first]
52
+ end
53
+
54
+ should "take translation and output internationalized html to display the translated text of the attributes" do
55
+ @translatable.translate(:label => 'une étiquette', :locale => 'fr').save
56
+ @translation = @translatable.translation_for(:fr)
57
+ array_with_hashes_of_translated_attributes_with_internationalized_names = [{:attribute_key=>:label, :localized_label => "Label", :value => "une étiquette"}]
58
+ # ignoring description for now (thus wrapped in array and .first)
59
+ assert_equal array_with_hashes_of_translated_attributes_with_internationalized_names, [translated_values_with_localized_labels.first]
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,342 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'test_helper'
3
+
4
+ class MongodbTranslatableTest < ActiveSupport::TestCase
5
+ context "A translation" do
6
+ setup do
7
+ I18n.locale = I18n.default_locale
8
+
9
+ @item = Factory.create(:item)
10
+
11
+ item_hash = Hash.new
12
+ item_hash[:label] = @item.attributes['label']
13
+ item_hash[:locale] = :fr
14
+ item_hash[@item.class.as_foreign_key_sym] = @item.id
15
+ @translation = @item.class::Translation.create(item_hash)
16
+ end
17
+
18
+ should "have a locale" do
19
+ if assert(@translation.respond_to?(:locale))
20
+ assert @translation.locale
21
+ end
22
+ end
23
+
24
+ should "have a translated object's translated attributes" do
25
+ assert @translation.attributes[Item.translatable_attributes.first]
26
+ end
27
+
28
+ should "be accessable from its item" do
29
+ if assert(@item.respond_to?(:translations))
30
+ assert @item.translation_for(I18n.locale)
31
+ end
32
+ end
33
+
34
+ should "be able to retrieve just the translated attribute" do
35
+ if assert(@item.respond_to?(:translations) && @item.respond_to?(:label_translation_for))
36
+ assert @item.label_translation_for(I18n.locale)
37
+ end
38
+ end
39
+
40
+ should "be able to retrieve its item from the item's persistence" do
41
+ assert @translation.translatable
42
+ end
43
+ end
44
+
45
+ context "When there is an Item needing translating" do
46
+ setup do
47
+ @item = Factory.create(:item, { :label => LOCALE_LABELS[:en] })
48
+ end
49
+
50
+ should "create translation" do
51
+ translate_item_for_locales(@item, :zh)
52
+ assert @item.translations.count == 1
53
+ end
54
+
55
+ should "not create translation if no translated text submitted" do
56
+ # arabic
57
+ I18n.locale = :ar
58
+ @item.translate
59
+ assert @item.translations.count == 0
60
+ end
61
+
62
+ should "not create translation if item's original_locale is same as translation locale" do
63
+ I18n.locale = :en
64
+ @item.translate(:label => LOCALE_LABELS[:en])
65
+ assert @item.translations.count == 0
66
+ end
67
+
68
+ should "create translation and it should reflect current locale" do
69
+ # french
70
+ translate_item_for_locales(@item, :fr)
71
+ assert @item.translation_for(:fr)
72
+ end
73
+
74
+ should "find item with the proper translation for current locale" do
75
+ translate_item_for_locales(@item, :fi)
76
+
77
+ # reloading item should detect current locale and pass back translated version of object
78
+ @item = Item.find(@item.id)
79
+
80
+ assert_equal @item.label, LOCALE_LABELS[:fi]
81
+ end
82
+
83
+ should "find item with the proper translation for current locale and fallback to original's value for translatable attribute that hasn't been translated" do
84
+ translate_item_for_locales(@item, :fi)
85
+
86
+ original_description = @item.description
87
+
88
+ # reloading item should detect current locale and pass back translated version of object
89
+ @item = Item.find(@item.id)
90
+
91
+ assert_equal @item.label, LOCALE_LABELS[:fi]
92
+ assert_equal original_description, @item.description
93
+ end
94
+
95
+ should "find item with the proper translation for current locale when there is more than one translation" do
96
+ # add a couple translations
97
+ translate_item_for_locales(@item, [:fi, :fr])
98
+
99
+ # then back to finnish
100
+ I18n.locale = :fi
101
+
102
+ # reloading item should detect current locale and pass back translated version of object
103
+ @item = Item.find(@item.id)
104
+
105
+ assert_equal @item.label, LOCALE_LABELS[:fi]
106
+ end
107
+
108
+ # test dynamic finder
109
+ should "find item with the proper translation for current locale when there is more than one translation and finding using dynamic finder" do
110
+ @item = Factory.create(:item, {:value => "a value"})
111
+
112
+ # add a couple translations
113
+ translate_item_for_locales(@item, [:fi, :fr])
114
+
115
+ # then back to finnish
116
+ I18n.locale = :fi
117
+
118
+ # reloading item should detect current locale and pass back translated version of object
119
+ @item = Item.find_by_value(@item.value)
120
+
121
+ assert_equal @item.label, LOCALE_LABELS[:fi]
122
+ end
123
+
124
+ should "after creating translations, if the item is destroyed, the translations are destroyed" do
125
+ # add a couple translations
126
+ translate_item_for_locales(@item, [:fi, :fr])
127
+
128
+ translations_ids = @item.translations.collect { |translation| translation.id }
129
+
130
+ @item.destroy
131
+
132
+ remaining_translations = Item::Translation.find(translations_ids)
133
+
134
+ assert_equal 0, remaining_translations.size
135
+ end
136
+
137
+ should "when the item is destroyed, when it has no translations, it should succeed in being destroyed" do
138
+ assert_equal 0, @item.translations.size
139
+ assert @item.destroy
140
+ end
141
+
142
+ teardown do
143
+ I18n.locale = @original_locale
144
+ end
145
+ end
146
+
147
+ context "When there are many items being translated" do
148
+ setup do
149
+ # TODO: pull out this locale, not sure why before_save filter is not being called
150
+ @original_locale = I18n.locale
151
+ end
152
+
153
+ should "find items with the proper translation for current locale" do
154
+ ids = many_setup
155
+
156
+ # reloading item should detect current locale and pass back translated version of object
157
+ @items = Item.find(ids)
158
+
159
+ many_tests
160
+ end
161
+
162
+ should "find items with the proper translation for current locale using dynamic finder" do
163
+ value = "a value"
164
+ many_setup({:value => value})
165
+
166
+ # reloading item should detect current locale and pass back translated version of object
167
+ @items = Item.find_all_by_value(value)
168
+
169
+ many_tests(:fi => 10)
170
+ end
171
+
172
+ teardown do
173
+ I18n.locale = @original_locale
174
+ end
175
+ end
176
+
177
+ context "translations for an item" do
178
+ setup do
179
+ I18n.locale = I18n.default_locale
180
+ @item = Factory.create(:item)
181
+ @translation_keys = LOCALE_LABELS.keys - [:en]
182
+ translate_item_for_locales(@item, @translation_keys)
183
+ end
184
+
185
+ should "be retrievable from translations method" do
186
+ assert_equal @translation_keys.size, @item.translations.size
187
+ end
188
+
189
+ should "hae just locales be retrievable from translations_locales method" do
190
+ # these should be partial objects and not have any values for other attributes
191
+ locale_keys = @item.translations_locales.collect { |translation| translation.locale.to_sym if translation.label.nil? }.compact
192
+
193
+ assert_equal 0, (@translation_keys - locale_keys).size
194
+ end
195
+
196
+ should "have translation locales plus original local be retrievable as available_in_these_locales" do
197
+ locale_keys = @item.available_in_these_locales.collect { |locale| locale.to_sym }
198
+
199
+ assert_equal 0, ( ([:en] + @translation_keys) - locale_keys ).size
200
+ end
201
+
202
+ should "have needed_in_these_locales method that returns locales that haven't been translated yet" do
203
+ Item::Translation.first(:item_id => @item.id, :locale => "zh").destroy
204
+ assert_equal [:zh], @item.needed_in_these_locales.collect { |locale| locale.to_sym }
205
+ end
206
+ end
207
+
208
+ context "A Translatable class that has a plural associated accessors (has_many) in another class through an association" do
209
+ setup do
210
+ I18n.locale = I18n.default_locale
211
+
212
+ @person = Factory.create(:person)
213
+ @item1 = Factory.create(:item, :person => @person)
214
+ @item2 = Factory.create(:item, :person => @person)
215
+
216
+ translate_item_for_locales(@item1, :fr)
217
+ end
218
+
219
+ should "get translated results from plural accessor" do
220
+ I18n.locale = :fr
221
+ results_with_one_translated_labels = [@item1.reload, @item2].collect(&:label)
222
+
223
+ assert_equal results_with_one_translated_labels, @person.items.collect(&:label)
224
+ end
225
+ end
226
+
227
+ context "A Translatable class that has a singular associated accessor (belongs_to, has_one) in another class through an association" do
228
+ setup do
229
+ I18n.locale = I18n.default_locale
230
+
231
+ @item = Factory.create(:item, :person => @person)
232
+ @comment = @item.comments.create(:subject => "usual mallarky")
233
+
234
+ translate_item_for_locales(@item, :fr)
235
+ end
236
+
237
+ should "get translated results from singular accessor" do
238
+ I18n.locale = :fr
239
+ translated_label = Item.find(@item).label
240
+ assert_equal translated_label, @comment.item.label
241
+ end
242
+ end
243
+
244
+ context "A Translatable class that has redefine_find == false" do
245
+ setup do
246
+ I18n.locale = I18n.default_locale
247
+ @record = Factory.create(:not_swapped_in_record)
248
+ record_hash = Hash.new
249
+ record_hash[:name] = @record.attributes['name']
250
+ record_hash[:locale] = :fr
251
+ record_hash[@record.class.as_foreign_key_sym] = @record.id
252
+ @no_find_translation = @record.class::Translation.create(record_hash)
253
+ end
254
+
255
+ should "not swap out locale specific translation for record when loaded from a translated locale" do
256
+ I18n.locale = :fr
257
+ @record.reload
258
+ assert_equal 'en', @record.locale
259
+ end
260
+ end
261
+
262
+ context "A Translatable class that has some translatable_attributes with key_type specified" do
263
+
264
+ should "have String for type of key without key_type specified (default)" do
265
+ assert_equal Recipe::Translation.keys['name'].type, String
266
+ end
267
+
268
+ should "have Array for type of key when " do
269
+ assert_equal Recipe::Translation.keys['steps'].type, Array
270
+ assert_equal Recipe::Translation.keys['ingredients'].type, Array
271
+ end
272
+
273
+ context "can create translations that" do
274
+ setup do
275
+ I18n.locale = I18n.default_locale
276
+ @recipe = Factory.create(:recipe)
277
+ end
278
+
279
+ should "return value in correct key type for translatable_attribute" do
280
+ assert_equal @recipe.steps, ["steps1 - 1", "steps1 - 2"]
281
+ assert_equal @recipe.ingredients, ["ingredients1 - 1", "ingredients1 - 2"]
282
+
283
+ fr_steps = ['fr step 1', 'fr step 2']
284
+ fr_ingredients = ['fr ingredient 1', 'fr ingredient 2']
285
+
286
+ @recipe_translation = @recipe.class::Translation.create(:name => @recipe.attributes['name'],
287
+ :steps => fr_steps,
288
+ :ingredients => fr_ingredients,
289
+ :locale => :fr,
290
+ @recipe.class.as_foreign_key_sym => @recipe.id)
291
+
292
+ @recipe_translation.reload
293
+
294
+ assert_equal fr_steps, @recipe_translation.steps
295
+ assert_equal fr_ingredients, @recipe_translation.ingredients
296
+ end
297
+
298
+ end
299
+ end
300
+
301
+ private
302
+
303
+ # see many_tests for what it expects
304
+ def many_setup(item_spec = nil)
305
+ ids = Array.new
306
+ 5.times do
307
+ I18n.locale = @original_locale
308
+ item = item_spec ? Factory.create(:item, item_spec) : Factory.create(:item)
309
+ translate_item_for_locales(item, [:ar, :fr])
310
+ ids << item.id
311
+ end
312
+
313
+ 5.times do
314
+ I18n.locale = @original_locale
315
+ item = item_spec ? Factory.create(:item, item_spec) : Factory.create(:item)
316
+ translate_item_for_locales(item, [:zh, :fi])
317
+ ids << item.id
318
+ end
319
+
320
+ # excluding these from ids searched
321
+ 5.times do
322
+ I18n.locale = @original_locale
323
+ item = item_spec ? Factory.create(:item, item_spec) : Factory.create(:item)
324
+ translate_item_for_locales(item, [:fr, :fi])
325
+ end
326
+
327
+ I18n.locale = :fi
328
+ ids
329
+ end
330
+
331
+ # expect 5 en, 5 finnish, and none in french, chinese, or arabic
332
+ def many_tests(passed_amounts = { })
333
+ results_number_for = { :fi => 5, :en => 5, :fr => 0, :ar => 0, :zh => 0}
334
+ results_number_for.merge!(passed_amounts)
335
+
336
+ assert_equal results_number_for[:fi], @items.select { |i| i.locale.to_sym == :fi }.size
337
+ assert_equal results_number_for[:en], @items.select { |i| i.locale.to_sym == :en }.size
338
+ assert_equal results_number_for[:fr], @items.select { |i| i.locale.to_sym == :fr }.size
339
+ assert_equal results_number_for[:ar], @items.select { |i| i.locale.to_sym == :ar }.size
340
+ assert_equal results_number_for[:zh], @items.select { |i| i.locale.to_sym == :zh }.size
341
+ end
342
+ end
@@ -0,0 +1,94 @@
1
+ module RoutingFilter
2
+ mattr_accessor :active
3
+ @@active = true
4
+
5
+ class Chain < Array
6
+ def << (filter)
7
+ filter.chain = self
8
+ super
9
+ end
10
+
11
+ def run(method, *args, &final)
12
+ RoutingFilter.active && !first.nil? ? first.run(method, *args, &final) : final.call
13
+ end
14
+
15
+ def run_reverse(method, *args, &final)
16
+ RoutingFilter.active && !last.nil? ? last.run_reverse(method, *args, &final) : final.call
17
+ end
18
+
19
+ def predecessor(filter)
20
+ ix = index(filter)
21
+ ix > 0 ? self[ix - 1] : nil
22
+ end
23
+
24
+ def successor(filter)
25
+ ix = index(filter)
26
+ ix < length - 1 ? self[ix + 1] : nil
27
+ end
28
+ end
29
+ end
30
+
31
+ # allows to install a filter to the route set by calling: map.filter 'locale'
32
+ ActionController::Routing::RouteSet::Mapper.class_eval do
33
+ def filter(name, options = {})
34
+ require options.delete(:file) || "routing_filter/#{name}"
35
+ klass = RoutingFilter.const_get(name.to_s.camelize)
36
+ @set.filters << klass.new(options)
37
+ end
38
+ end
39
+
40
+ # same here for the optimized url generation in named routes
41
+ ActionController::Routing::RouteSet::NamedRouteCollection.class_eval do
42
+ # gosh. monkey engineering optimization code
43
+ def generate_optimisation_block_with_filtering(*args)
44
+ code = generate_optimisation_block_without_filtering(*args)
45
+ if match = code.match(%r(^return (.*) if (.*)))
46
+ # returned string must not contain newlines, or we'll spill out of inline code comments in
47
+ # ActionController::Routing::RouteSet::NamedRouteCollection#define_url_helper
48
+ "returning(#{match[1]}) { |result|" +
49
+ " ActionController::Routing::Routes.filters.run_reverse(:around_generate, *args, &lambda{ result }) " +
50
+ "} if #{match[2]}"
51
+ end
52
+ end
53
+ alias_method_chain :generate_optimisation_block, :filtering
54
+ end
55
+
56
+ ActionController::Routing::RouteSet.class_eval do
57
+ def clear_with_filtering!
58
+ @filters.clear if @filters
59
+ clear_without_filtering!
60
+ end
61
+ alias_method_chain :clear!, :filtering
62
+
63
+ attr_writer :filters
64
+
65
+ def filters
66
+ @filters ||= RoutingFilter::Chain.new
67
+ end
68
+
69
+ def recognize_path_with_filtering(path, env = {})
70
+ path = ::URI.unescape(path.dup) # string is frozen due to memoize
71
+ filters.run(:around_recognize, path, env, &lambda{ recognize_path_without_filtering(path, env) })
72
+ end
73
+ alias_method_chain :recognize_path, :filtering
74
+
75
+ def generate_with_filtering(*args)
76
+ filters.run_reverse(:around_generate, args.first, &lambda{ generate_without_filtering(*args) })
77
+ end
78
+ alias_method_chain :generate, :filtering
79
+
80
+ # add some useful information to the request environment
81
+ # right, this is from jamis buck's excellent article about routes internals
82
+ # http://weblog.jamisbuck.org/2006/10/26/monkey-patching-rails-extending-routes-2
83
+ # TODO move this ... where?
84
+ alias_method :extract_request_environment_without_host, :extract_request_environment unless method_defined? :extract_request_environment_without_host
85
+ def extract_request_environment(request)
86
+ returning extract_request_environment_without_host(request) do |env|
87
+ env.merge! :host => request.host,
88
+ :port => request.port,
89
+ :host_with_port => request.host_with_port,
90
+ :domain => request.domain,
91
+ :subdomain => request.subdomains.first
92
+ end
93
+ end
94
+ end