translated_attributes 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIGRATION ADDED
@@ -0,0 +1,18 @@
1
+ class AddTranslations < ActiveRecord::Migration
2
+ def self.up
3
+ #you can remove the limit/null constrains
4
+ #this is simply my recommended way of setting things up (save + limits needed storage space)
5
+ create_table :translations do |t|
6
+ t.column :translatable_id, :integer, :null=>false
7
+ t.column :translatable_type, :string, :limit=>40, :null=>false
8
+ t.column :language, :string, :limit=>2, :null=>false
9
+ t.column :attribute, :string, :limit=>40, :null=>false
10
+ t.column :text, :text, :null=>false
11
+ end
12
+ add_index :translations, [:translatable_id, :translatable_type]
13
+ end
14
+
15
+ def self.down
16
+ drop_table :translations
17
+ end
18
+ end
data/README.markdown ADDED
@@ -0,0 +1,49 @@
1
+ Rails plugin/ActiveRecord gem that creates 'virtual' attributes, which can be added on the fly without overhead or migrations, while storing all the data in a never-changing translations table.
2
+ This keeps the attatched model light and allows to add/remove fields on the fly without migrations.
3
+
4
+ Validations work like normal with current field (e.g. title) or any translation (e.g. title_in_en)
5
+
6
+ Usage
7
+ =====
8
+ - As Rails plugin `script/plugin install git://github.com/grosser/translated_attributes.git`
9
+ - As gem `sudo gem install translated_attributes`
10
+ - execute MIGRATION
11
+
12
+ Adding attributes:
13
+ class Product < ActiveRecord::Base
14
+ translated_attributes :description, :title, :additional_info
15
+ end
16
+
17
+ Setting / getting
18
+ #getter
19
+ product.title -> 'Hello' #when I18n.locale is :en
20
+ product.title_in_fr -> 'Bonyour'
21
+ product.title_in_de -> 'Hallo'
22
+
23
+ #setter
24
+ product.title = 'Simple setting' #sets title_in_en when I18n.locale == :en
25
+ product.title_in_de = 'Spezifisches speichern'
26
+
27
+ #generic setter/getter
28
+ product.set_title('Specific setting', :en)
29
+ product.get_title(:en) -> 'Specific setting'
30
+
31
+ Usage with saving works exactly like normal saving, e.g. new/create/update_attributes...
32
+ Product.new(:title_in_en=>'Hello').save!
33
+ product.update_attribute(:title, 'Goodbye')
34
+
35
+ - Translations are stored on 'save'
36
+ - blank translations are NOT stored
37
+ - translations are accessable via .translations or as hash via .translated_attributes
38
+
39
+ Options
40
+ =======
41
+ translated_attributes :title, :heading,
42
+ :table_name => 'user_translations', #default is translations
43
+ :nil_to_blank => true, #return unfound translations as blank strings ('') instead of nil (default false),
44
+ :translatable_name => 'translated' #name of the associated translatable (Product has_many :translations a Translation belongs_to XXX), default is :translatable
45
+ Author
46
+ ======
47
+ [Michael Grosser](http://pragmatig.wordpress.com)
48
+ grosser.michael@gmail.com
49
+ Hereby placed under public domain, do what you want, just do not hold me accountable...
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ desc "Run all specs in spec directory"
2
+ task :default do
3
+ options = "--colour --format progress --loadby --reverse"
4
+ files = FileList['spec/**/*_spec.rb']
5
+ system("spec #{options} #{files}")
6
+ end
7
+
8
+ begin
9
+ project_name = 'translated_attributes'
10
+ require 'jeweler'
11
+ Jeweler::Tasks.new do |gem|
12
+ gem.name = project_name
13
+ gem.summary = "ActiveRecord/Rails simple translatable attributes"
14
+ gem.email = "grosser.michael@gmail.com"
15
+ gem.homepage = "http://github.com/grosser/#{project_name}"
16
+ gem.authors = ["Michael Grosser"]
17
+ gem.files += (FileList["{lib,spec}/**/*"] + FileList["VERSION"] + FileList["README.markdown"]).to_a.sort
18
+ gem.add_dependency ['activerecord']
19
+ gem.rubyforge_project = 'translated-attr'
20
+ end
21
+
22
+ # fake task so that rubyforge:release works
23
+ task :rdoc do
24
+ `mkdir rdoc`
25
+ `echo documentation is at http://github.com/grosser/#{project_name} > rdoc/README.rdoc`
26
+ end
27
+
28
+ Jeweler::RubyforgeTasks.new
29
+ rescue LoadError
30
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
31
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.1
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ #Needed to load when used as Rails plugin
2
+ require 'translated_attributes'
@@ -0,0 +1,152 @@
1
+ module TranslatedAttributes
2
+ module ClassMethods
3
+ # translated_attributes :title, :description, :table_name=>'my_translations'
4
+ def translated_attributes(*args)
5
+ #store options
6
+ cattr_accessor :translated_attributes_options
7
+ options = args.extract_options! || {}
8
+ self.translated_attributes_options = options.merge(:fields=>args.map(&:to_sym))
9
+
10
+ #create translations class
11
+ table_name = options[:table_name] || :translations
12
+ class_name = table_name.to_s.classify
13
+
14
+ associated = options[:translatable_name] || :translatable
15
+ begin
16
+ klass = Object.const_get(class_name)
17
+ rescue
18
+ klass = Class.new(ActiveRecord::Base)
19
+ Object.const_set(class_name, klass)
20
+ klass.set_table_name table_name
21
+ klass.belongs_to associated, :polymorphic => true
22
+ end
23
+
24
+ #set translations
25
+ has_many :translations, :as => associated, :dependent => :delete_all, :class_name=>klass.name
26
+
27
+ #include methods
28
+ include TranslatedAttributes::InstanceMethods
29
+ end
30
+ end
31
+
32
+ module InstanceMethods
33
+ def self.included(base)
34
+ fields = base.translated_attributes_options[:fields]
35
+ fields.each do |field|
36
+ base.class_eval <<-GETTER_AND_SETTER
37
+ def get_#{field}(locale=nil)
38
+ get_translated_attribute(locale, :#{field})
39
+ end
40
+
41
+ def set_#{field}(value, locale=I18n.locale)
42
+ set_translated_attribute(locale, :#{field}, value)
43
+ end
44
+
45
+ #generic aliases (and since e.g. title=(a,b) would not be possible)
46
+ alias #{field} get_#{field}
47
+ alias #{field}= set_#{field}
48
+ GETTER_AND_SETTER
49
+ end
50
+
51
+ base.after_save :store_translated_attributes
52
+ end
53
+
54
+ def get_translated_attribute(locale, field)
55
+ text = if locale
56
+ translated_attributes_for(locale)[field]
57
+ else
58
+ #try to find anything...
59
+ #current, english, anything else
60
+ found = translated_attributes_for(I18n.locale)[field] || translated_attributes_for(:en)[field]
61
+ if found
62
+ found
63
+ else
64
+ found = translated_attributes.detect{|locale, attributes| not attributes[field].blank?}
65
+ found ? found[1][field] : nil
66
+ end
67
+ end
68
+
69
+ if self.class.translated_attributes_options[:nil_to_blank]
70
+ text || ''
71
+ else
72
+ text
73
+ end
74
+ end
75
+
76
+ def set_translated_attribute(locale, field, value)
77
+ return if translated_attributes_for(locale)[field] == value
78
+ translated_attributes_for(locale)[field] = value
79
+ @translated_attributes_changed = true
80
+ end
81
+
82
+ def translated_attributes
83
+ merge_db_translations_with_instance_variable
84
+ @translated_attributes ||= {}.with_indifferent_access
85
+ end
86
+
87
+ def translated_attributes= hash
88
+ @db_translations_merged = true #do not overwrite what we set here
89
+ @translated_attributes_changed = true #store changes we made
90
+ @translated_attributes = hash.with_indifferent_access
91
+ end
92
+
93
+ def respond_to?(name, *args)
94
+ return true if parse_translated_attribute_method(name)
95
+ super
96
+ end
97
+
98
+ def method_missing(name, *args)
99
+ field, locale = parse_translated_attribute_method(name)
100
+ return super unless field
101
+ if name.to_s.include? '=' #is setter ?
102
+ send("set_#{field}", args[0], locale)
103
+ else
104
+ send("get_#{field}", locale)
105
+ end
106
+ end
107
+
108
+ protected
109
+
110
+ def store_translated_attributes
111
+ return true unless @translated_attributes_changed
112
+ translations.delete_all
113
+ @translated_attributes.each do |locale, attributes|
114
+ attributes.each do |attribute, value|
115
+ next if value.blank?
116
+ next unless self.class.translated_attributes_options[:fields].include? attribute.to_sym
117
+ translations.create!(:attribute=>attribute, :text=>value, :language=>locale)
118
+ end
119
+ end
120
+ @translated_attributes_changed = false
121
+ end
122
+
123
+ private
124
+
125
+ def merge_db_translations_with_instance_variable
126
+ return if new_record? or @db_translations_merged
127
+ @db_translations_merged = true
128
+ translations.all.each do |t|
129
+ translated_attributes_for(t.language)[t.attribute] = t.text
130
+ end
131
+ end
132
+
133
+ def parse_translated_attribute_method(name)
134
+ return false if name.to_s !~ /^([a-zA-Z_]+)_in_([a-z]{2})[=]?$/
135
+ field = $1; locale = $2
136
+ return false unless is_translated_attribute?(field)
137
+ return field, locale
138
+ end
139
+
140
+ def is_translated_attribute?(method_name)
141
+ fields = self.class.translated_attributes_options[:fields]
142
+ fields.include? method_name.sub('=','').to_sym
143
+ end
144
+
145
+ def translated_attributes_for(locale)
146
+ translated_attributes[locale] ||= {}.with_indifferent_access
147
+ translated_attributes[locale]
148
+ end
149
+ end
150
+ end
151
+
152
+ ActiveRecord::Base.send :extend, TranslatedAttributes::ClassMethods
@@ -0,0 +1,42 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe 'Integration' do
4
+ before do
5
+ Translation.delete_all
6
+ UserTranslation.delete_all
7
+ end
8
+
9
+ it "manages different translations appropriatly" do
10
+ User.create(:name_in_en=>'User1NameEn', :name_in_de=>'User1NameDe')
11
+ User.create(:name_in_en=>'User2NameEn', :name_in_fr=>'User2NameFr')
12
+ Product.create(:title=>'Product1TitleEn', :title_in_de=>'Product1TitleDe')
13
+
14
+ User.first.translated_attributes = {}
15
+ u = User.last
16
+ u.translated_attributes = {:fr=>{:name=>'User1NameFr'}}
17
+ u.save!
18
+
19
+ UserTranslation.count.should == 3
20
+ Translation.count.should == 2
21
+ User.last.name.should == 'User1NameFr'
22
+ end
23
+
24
+ it "cleans up translations" do
25
+ User.create!(:name=>'u1')
26
+ Product.create!(:title=>'p1',:description=>'d1')
27
+ Product.create!(:title=>'p2')
28
+
29
+ Translation.count.should == 3
30
+ UserTranslation.count.should == 1
31
+
32
+ Product.destroy_all
33
+
34
+ Translation.count.should == 0
35
+ UserTranslation.count.should == 1
36
+
37
+ User.destroy_all
38
+
39
+ Translation.count.should == 0
40
+ UserTranslation.count.should == 0
41
+ end
42
+ end
data/spec/models.rb ADDED
@@ -0,0 +1,31 @@
1
+ ActiveRecord::Schema.define(:version => 1) do
2
+ create_table :users do |t|
3
+ end
4
+
5
+ create_table :products do |t|
6
+ end
7
+
8
+ %w[translations user_translations].each do |table|
9
+ create_table table do |t|
10
+ t.integer :translatable_id, :null=>false
11
+ t.string :translatable_type, :limit=>40, :null=>false
12
+ t.string :language, :limit=>2, :null=>false
13
+ t.string :attribute, :limit=>40, :null=>false
14
+ t.text :text, :null=>false
15
+ end
16
+ end
17
+ end
18
+
19
+ #create model
20
+ class User < ActiveRecord::Base
21
+ translated_attributes :name, :table_name=>:user_translations, :nil_to_blank=>true
22
+ end
23
+
24
+ class Shop < ActiveRecord::Base
25
+ set_table_name :products
26
+ translated_attributes :shop_name
27
+ end
28
+
29
+ class Product < ActiveRecord::Base
30
+ translated_attributes :title, :description
31
+ end
@@ -0,0 +1,18 @@
1
+ # ---- requirements
2
+ require 'rubygems'
3
+ require 'spec'
4
+ require 'activerecord'
5
+
6
+ $LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
7
+
8
+ # ---- setup environment/plugin
9
+ ActiveRecord::Base.establish_connection({
10
+ :adapter => "sqlite3",
11
+ :database => ":memory:",
12
+ })
13
+
14
+ #ActiveRecord::Base.logger = Logger.new(STDOUT)
15
+
16
+ require File.expand_path("../init", File.dirname(__FILE__))
17
+
18
+ require 'spec/models'
@@ -0,0 +1,304 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe 'Translated attributes' do
4
+ before do
5
+ I18n.locale = :en
6
+ end
7
+
8
+ describe 'caching' do
9
+ it "is nil when nothing is set" do
10
+ Product.new.title.should == nil
11
+ Product.new.description.should == nil
12
+ end
13
+
14
+ it 'can be set' do
15
+ p = Product.new
16
+ p.title = 'abc'
17
+ p.title.should == 'abc'
18
+ end
19
+
20
+ it 'can be overwritten' do
21
+ p = Product.new
22
+ p.title = 'abc'
23
+ p.title = 'def'
24
+ p.title.should == 'def'
25
+ end
26
+
27
+ it "ca be unset" do
28
+ p = Product.new
29
+ p.title = 'abc'
30
+ p.title = nil
31
+ p.title.should == nil
32
+ end
33
+
34
+ it "sets the current language" do
35
+ p = Product.new
36
+ p.title = 'abc'
37
+ p.title_in_en.should == 'abc'
38
+ end
39
+
40
+ it "can be set in different languages" do
41
+ p = Product.new
42
+ p.title = 'abc'
43
+ p.title_in_de.should == nil
44
+ I18n.locale = :de
45
+ p.title = 'bcd'
46
+ p.title_in_de.should == 'bcd'
47
+ end
48
+
49
+ it "returns current language when current can be found" do
50
+ I18n.locale = :de
51
+ p = Product.new
52
+ p.title_in_de = 'abc'
53
+ p.title_in_en = 'def'
54
+ p.title.should == 'abc'
55
+ end
56
+
57
+ it "returns english translation when current cannot be found" do
58
+ I18n.locale = :de
59
+ p = Product.new
60
+ p.title_in_en = 'abc'
61
+ p.title.should == 'abc'
62
+ end
63
+
64
+ it "returns any translation when current and english cannot be found" do
65
+ I18n.locale = :fr
66
+ p = Product.new
67
+ p.title_in_de = 'abc'
68
+ p.title.should == 'abc'
69
+ end
70
+ end
71
+
72
+ describe 'storing' do
73
+ it "stores nothing when nothing was set" do
74
+ lambda{ Product.create! }.should_not change(Translation, :count)
75
+ Product.last.title.should == nil
76
+ end
77
+
78
+ it "stores column as translation on save" do
79
+ lambda{ Product.create!(:title=>'x') }.should change(Translation, :count).by(+1)
80
+ end
81
+
82
+ it "stores nothing when blank was set" do
83
+ lambda{ Product.create! :title=>' ' }.should_not change(Translation, :count)
84
+ Product.last.title.should == nil
85
+ end
86
+
87
+ it "creates no translation when validations fail" do
88
+ p = Product.new :title=>'xxx'
89
+ p.should_receive(:valid?).and_return false
90
+ lambda{ p.save }.should_not change(Translation, :count)
91
+ end
92
+
93
+ it "is stored after save" do
94
+ p = Product.create!(:title=>'1')
95
+ p.title = '2'
96
+ p.save!
97
+ Product.last.title.should == '2'
98
+ end
99
+
100
+ it "does not create unecessary translations on change" do
101
+ p = Product.create!(:title=>'1')
102
+ lambda{
103
+ p.title = '2'
104
+ p.save!
105
+ }.should_not change(Translation, :count)
106
+ end
107
+
108
+ it "does not update translations when nothing changed" do
109
+ p = Product.create!(:title=>'xx')
110
+ p.title = 'xx'
111
+ lambda{ p.save }.should_not change{Translation.last.id}
112
+ end
113
+
114
+ it "works through update_attribute" do
115
+ p = Product.create!(:title=>'xx', :description=>'dd')
116
+ p.update_attribute(:title, 'yy')
117
+ Product.last.title.should == 'yy'
118
+ Product.last.description.should == 'dd'
119
+ end
120
+
121
+ it "works through update_attributes" do
122
+ p = Product.create!(:title=>'xx', :description=>'dd')
123
+ p.update_attributes(:title=>'yy')
124
+ Product.last.title.should == 'yy'
125
+ Product.last.description.should == 'dd'
126
+ end
127
+
128
+ it "works through attributes=" do
129
+ p = Product.create!(:title=>'xx', :description=>'dd')
130
+ p.attributes = {:title=>'yy'}
131
+ p.save!
132
+ Product.last.title.should == 'yy'
133
+ Product.last.description.should == 'dd'
134
+ end
135
+
136
+ it "loads translations once" do
137
+ Product.create!(:title=>'xx', :description=>'yy')
138
+ p = Product.last
139
+ p.translations.should_receive(:all).and_return []
140
+ p.title.should == nil
141
+ p.description.should == nil
142
+ end
143
+
144
+ it "deletes the existing translation when changing to blank" do
145
+ p = Product.create!(:title=>'1')
146
+ lambda{
147
+ p.title = ''
148
+ p.save!
149
+ }.should change(Translation, :count).by(-1)
150
+ Product.last.title.should == nil
151
+ end
152
+
153
+ it "can store multiple translations at once" do
154
+ lambda{
155
+ Product.create!(:title_in_de=>'Hallo', :title_in_en=>'Hello')
156
+ }.should change(Translation, :count).by(+2)
157
+ Product.last.title_in_de.should == 'Hallo'
158
+ Product.last.title.should == 'Hello'
159
+ end
160
+
161
+ it "deletes translations when translatable is destroyed" do
162
+ Translation.delete_all
163
+ Product.create!(:title=>'t1')
164
+ Product.create!(:title=>'t2',:description=>'d2')
165
+ Translation.count.should == 3
166
+
167
+ Product.last.destroy
168
+
169
+ Translation.count.should == 1
170
+ Translation.first.text.should == 't1'
171
+ end
172
+
173
+ it "is not influenced by reloading" do
174
+ p = Product.create!(:title=>'t1', :description=>'d1')
175
+ p.title = 't2'
176
+ p.reload
177
+ p.description = 'd2'
178
+ p.save!
179
+ Product.last.title.should == 't2'
180
+ Product.last.description.should == 'd2'
181
+ end
182
+ end
183
+
184
+ describe 'classes' do
185
+ it "does not define them twice" do
186
+ Translation.instance_variable_set '@test', 1
187
+ class XXX < ActiveRecord::Base
188
+ set_table_name :products
189
+ translated_attributes :name
190
+ end
191
+ Translation.instance_variable_get('@test').should == 1
192
+ end
193
+
194
+ it "stores options seperately" do
195
+ Shop.translated_attributes_options[:fields].should_not == Product.translated_attributes_options[:fields]
196
+ end
197
+ end
198
+
199
+ describe 'different tables' do
200
+ it "creates the model for each table_name" do
201
+ Translation
202
+ UserTranslation
203
+ end
204
+
205
+ it "creates translations in set table" do
206
+ Product.create!(:title=>'yyy')
207
+ Translation.last.text.should == 'yyy'
208
+
209
+ User.create!(:name=>'xxx')
210
+ UserTranslation.last.text.should == 'xxx'
211
+ end
212
+ end
213
+
214
+ describe 'nil to blank' do
215
+ it "converts all unfound fields to blank" do
216
+ User.new.name.should == ''
217
+ end
218
+ end
219
+
220
+ describe :translated_attributes do
221
+ it "is a empty hash when nothing was set" do
222
+ Product.new.translated_attributes.should == {}
223
+ end
224
+
225
+ it "can be modified" do
226
+ Product.new.translated_attributes.should_not be_frozen
227
+ end
228
+ end
229
+
230
+ describe :translated_attriutes= do
231
+ it "stores all translations" do
232
+ p = Product.create!
233
+ p.translated_attributes = {:de=>{:title=>'de title',:description=>'de descr'}}
234
+ p.title_in_de.should == 'de title'
235
+ p.description_in_de.should == 'de descr'
236
+ p.title_in_en.should == nil
237
+ end
238
+
239
+ it "overwrites existing translations" do
240
+ p = Product.create!(:title=>'en title')
241
+ p.translated_attributes = {:de=>{:title=>'de title',:description=>'de descr'}}
242
+ p.title_in_de.should == 'de title'
243
+ p.description_in_de.should == 'de descr'
244
+ p.title_in_en.should == nil
245
+ end
246
+
247
+ it "stores and overwrites on save" do
248
+ p = Product.create!(:title=>'en title')
249
+ p.translated_attributes = {:de=>{:title=>'de title',:description=>'de descr'}}
250
+ p.save!
251
+ Product.last.title.should == 'de title'
252
+ Product.last.title_in_de.should == 'de title'
253
+ end
254
+
255
+ it "does not store unknown attributes" do
256
+ p = Product.new
257
+ p.translated_attributes = {:de=>{:xxx=>'de title',:description=>'de descr'}}
258
+ lambda{
259
+ p.save!
260
+ }.should change(Translation, :count).by(+1)
261
+ end
262
+
263
+ it "does not alter the given hash" do
264
+ p = Product.create!(:title=>'en title')
265
+ hash = {:de=>{:title=>'de title',:description=>'de descr'}}
266
+ p.translated_attributes = hash
267
+ hash['de'].should == nil #not converted to indifferent access
268
+ hash[:de][:title].should == 'de title' #still has all attributes
269
+ end
270
+
271
+ it "stores given hash indifferent" do
272
+ p = Product.new
273
+ p.translated_attributes = {'de'=>{'title'=>'title de'}}
274
+ p.translated_attributes[:de][:title].should == 'title de'
275
+ end
276
+ end
277
+
278
+ describe :method_missing do
279
+ it "ignores calls without _in_" do
280
+ lambda{Product.new.title_xxx}.should raise_error
281
+ end
282
+ it "ignores calls with a non-supported attribute" do
283
+ lambda{Product.new.foo_in_de}.should raise_error
284
+ end
285
+ end
286
+
287
+ describe :respond_to? do
288
+ it "ignores calls without _in_" do
289
+ Product.new.respond_to?(:title_xx_xx).should == false
290
+ end
291
+
292
+ it "ignores calls with a non-supported attribute" do
293
+ Product.new.respond_to?(:foo_in_de).should == false
294
+ end
295
+
296
+ it "responds to translated column" do
297
+ Product.new.respond_to?(:title_in_en).should == true
298
+ end
299
+
300
+ it "responds to normal methods" do
301
+ Product.new.respond_to?(:new_record?).should == true
302
+ end
303
+ end
304
+ end
@@ -0,0 +1,62 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{translated_attributes}
8
+ s.version = "0.5.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Grosser"]
12
+ s.date = %q{2009-10-16}
13
+ s.email = %q{grosser.michael@gmail.com}
14
+ s.extra_rdoc_files = [
15
+ "README.markdown"
16
+ ]
17
+ s.files = [
18
+ "MIGRATION",
19
+ "README.markdown",
20
+ "README.markdown",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "VERSION",
24
+ "init.rb",
25
+ "lib/translated_attributes.rb",
26
+ "lib/translated_attributes.rb",
27
+ "spec/integration_spec.rb",
28
+ "spec/integration_spec.rb",
29
+ "spec/models.rb",
30
+ "spec/models.rb",
31
+ "spec/spec_helper.rb",
32
+ "spec/spec_helper.rb",
33
+ "spec/translated_attributes_spec.rb",
34
+ "spec/translated_attributes_spec.rb",
35
+ "translated_attributes.gemspec"
36
+ ]
37
+ s.homepage = %q{http://github.com/grosser/translated_attributes}
38
+ s.rdoc_options = ["--charset=UTF-8"]
39
+ s.require_paths = ["lib"]
40
+ s.rubyforge_project = %q{translated-attr}
41
+ s.rubygems_version = %q{1.3.5}
42
+ s.summary = %q{ActiveRecord/Rails simple translatable attributes}
43
+ s.test_files = [
44
+ "spec/integration_spec.rb",
45
+ "spec/spec_helper.rb",
46
+ "spec/translated_attributes_spec.rb",
47
+ "spec/models.rb"
48
+ ]
49
+
50
+ if s.respond_to? :specification_version then
51
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
52
+ s.specification_version = 3
53
+
54
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
55
+ s.add_runtime_dependency(%q<activerecord>, [">= 0"])
56
+ else
57
+ s.add_dependency(%q<activerecord>, [">= 0"])
58
+ end
59
+ else
60
+ s.add_dependency(%q<activerecord>, [">= 0"])
61
+ end
62
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: translated_attributes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.1
5
+ platform: ruby
6
+ authors:
7
+ - Michael Grosser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-16 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email: grosser.michael@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.markdown
33
+ files:
34
+ - MIGRATION
35
+ - README.markdown
36
+ - Rakefile
37
+ - VERSION
38
+ - init.rb
39
+ - lib/translated_attributes.rb
40
+ - spec/integration_spec.rb
41
+ - spec/models.rb
42
+ - spec/spec_helper.rb
43
+ - spec/translated_attributes_spec.rb
44
+ - translated_attributes.gemspec
45
+ has_rdoc: true
46
+ homepage: http://github.com/grosser/translated_attributes
47
+ licenses: []
48
+
49
+ post_install_message:
50
+ rdoc_options:
51
+ - --charset=UTF-8
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ requirements: []
67
+
68
+ rubyforge_project: translated-attr
69
+ rubygems_version: 1.3.5
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: ActiveRecord/Rails simple translatable attributes
73
+ test_files:
74
+ - spec/integration_spec.rb
75
+ - spec/spec_helper.rb
76
+ - spec/translated_attributes_spec.rb
77
+ - spec/models.rb