globalize3 0.1.0.beta → 0.1.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,55 +1,57 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- globalize3 (0.0.10)
4
+ globalize3 (0.1.0.beta2)
5
5
  activemodel (>= 3.0.0)
6
6
  activerecord (>= 3.0.0)
7
7
 
8
8
  GEM
9
9
  remote: http://rubygems.org/
10
10
  specs:
11
- activemodel (3.0.3)
12
- activesupport (= 3.0.3)
11
+ activemodel (3.0.7)
12
+ activesupport (= 3.0.7)
13
13
  builder (~> 2.1.2)
14
- i18n (~> 0.4)
15
- activerecord (3.0.3)
16
- activemodel (= 3.0.3)
17
- activesupport (= 3.0.3)
14
+ i18n (~> 0.5.0)
15
+ activerecord (3.0.7)
16
+ activemodel (= 3.0.7)
17
+ activesupport (= 3.0.7)
18
18
  arel (~> 2.0.2)
19
19
  tzinfo (~> 0.3.23)
20
- activesupport (3.0.3)
21
- arel (2.0.6)
20
+ activesupport (3.0.7)
21
+ archive-tar-minitar (0.5.2)
22
+ arel (2.0.10)
22
23
  builder (2.1.2)
23
24
  columnize (0.3.2)
24
25
  database_cleaner (0.5.2)
25
26
  i18n (0.5.0)
26
- linecache (0.43)
27
+ linecache19 (0.5.11)
28
+ ruby_core_source (>= 0.1.4)
27
29
  mocha (0.9.10)
28
30
  rake
29
31
  pathname_local (0.0.2)
30
32
  rake (0.8.7)
31
- ruby-debug (0.10.4)
32
- columnize (>= 0.1)
33
- ruby-debug-base (~> 0.10.4.0)
34
- ruby-debug-base (0.10.4)
35
- linecache (>= 0.3)
33
+ ruby-debug-base19 (0.11.24)
34
+ columnize (>= 0.3.1)
35
+ linecache19 (>= 0.5.11)
36
+ ruby_core_source (>= 0.1.4)
37
+ ruby-debug19 (0.11.6)
38
+ columnize (>= 0.3.1)
39
+ linecache19 (>= 0.5.11)
40
+ ruby-debug-base19 (>= 0.11.19)
41
+ ruby_core_source (0.1.4)
42
+ archive-tar-minitar (>= 0.5.2)
36
43
  sqlite3-ruby (1.3.2)
37
- test_declarative (0.0.4)
38
- tzinfo (0.3.23)
44
+ test_declarative (0.0.5)
45
+ tzinfo (0.3.27)
39
46
 
40
47
  PLATFORMS
41
48
  ruby
42
49
 
43
50
  DEPENDENCIES
44
- activemodel (>= 3.0.0)
45
- activerecord (>= 3.0.0)
46
51
  database_cleaner (= 0.5.2)
47
52
  globalize3!
48
53
  mocha
49
54
  pathname_local
50
- ruby-debug
55
+ ruby-debug19
51
56
  sqlite3-ruby
52
57
  test_declarative
53
-
54
- METADATA
55
- version: 1.0.6
data/README.textile CHANGED
@@ -62,7 +62,7 @@ As well as creating a translation table, you can also use @create_translation_ta
62
62
  existing data to the default locale. This can also operate in reverse to restore any translations from the default locale
63
63
  back to the model when you don't want to use a translation table anymore using @drop_translation_table!@
64
64
 
65
- This feature makes use of @untranslated_fields@ which allows access to the model's attributes as they were before
65
+ This feature makes use of @untranslated_attributes@ which allows access to the model's attributes as they were before
66
66
  the translation was applied. Here's an example (which assumes you already have a model called @Post@ and its table exists):
67
67
 
68
68
  <pre><code>
@@ -7,7 +7,7 @@ module Globalize
7
7
  options = attr_names.extract_options!
8
8
  options[:table_name] ||= "#{table_name.singularize}_translations"
9
9
 
10
- class_inheritable_accessor :translated_attribute_names, :translation_options
10
+ class_attribute :translated_attribute_names, :translation_options
11
11
  self.translated_attribute_names = attr_names.map(&:to_sym)
12
12
  self.translation_options = options
13
13
 
@@ -19,14 +19,17 @@ module Globalize
19
19
  :dependent => :delete_all,
20
20
  :extend => HasManyExtensions
21
21
 
22
- after_save :save_translations!
22
+ after_create :save_translations!
23
+ after_update :save_translations!
23
24
 
24
25
  attr_names.each { |attr_name| translated_attr_accessor(attr_name) }
25
26
  end
26
27
 
27
28
  def class_name
28
- class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].downcase.camelize
29
- pluralize_table_names ? class_name.singularize : class_name
29
+ @class_name ||= begin
30
+ class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].downcase.camelize
31
+ pluralize_table_names ? class_name.singularize : class_name
32
+ end
30
33
  end
31
34
 
32
35
  def translates?
@@ -3,25 +3,36 @@ module Globalize
3
3
  class Adapter
4
4
  # The cache caches attributes that already were looked up for read access.
5
5
  # The stash keeps track of new or changed values that need to be saved.
6
- attr_reader :record, :cache, :stash
6
+ attr_accessor :record, :stash, :translations
7
+ private :record=, :stash=
7
8
 
8
9
  delegate :translation_class, :to => :'record.class'
9
10
 
10
11
  def initialize(record)
11
- @record = record
12
- @cache = Attributes.new
13
- @stash = Attributes.new
12
+ self.record = record
13
+ self.stash = Attributes.new
14
+ end
15
+
16
+ def fetch_stash(locale, name)
17
+ value = stash.read(locale, name)
18
+ return value if value
19
+ return nil
14
20
  end
15
21
 
16
22
  def fetch(locale, name)
17
- cache.contains?(locale, name) ?
18
- type_cast(name, cache.read(locale, name)) :
19
- cache.write(locale, name, fetch_attribute(locale, name))
23
+ Globalize.fallbacks(locale).each do |fallback|
24
+ value = fetch_stash(fallback, name) || fetch_attribute(fallback, name)
25
+
26
+ if value
27
+ set_metadata(value, :locale => fallback, :requested_locale => locale)
28
+ return value
29
+ end
30
+ end
31
+ return nil
20
32
  end
21
33
 
22
34
  def write(locale, name, value)
23
35
  stash.write(locale, name, value)
24
- cache.write(locale, name, value)
25
36
  end
26
37
 
27
38
  def save_translations!
@@ -30,71 +41,50 @@ module Globalize
30
41
  attrs.each { |name, value| translation[name] = value }
31
42
  translation.save!
32
43
  end
44
+ record.translations.reset
33
45
  stash.clear
34
46
  end
35
47
 
36
48
  def reset
37
- cache.clear
49
+ stash.clear
38
50
  end
39
51
 
40
- protected
41
-
42
- def type_cast(name, value)
43
- if value.nil?
44
- nil
45
- elsif column = column_for_attribute(name)
46
- column.type_cast(value)
47
- else
48
- value
49
- end
50
- end
51
-
52
- def column_for_attribute(name)
53
- translation_class.columns_hash[name.to_s]
54
- end
55
-
56
- def unserializable_attribute?(name, column)
57
- column.text? && translation_class.serialized_attributes[name.to_s]
58
- end
59
-
60
- def fetch_translation(locale)
61
- locale = locale.to_sym
62
- record.translations.loaded? ? record.translations.detect { |t| t.locale == locale } :
63
- record.translations.with_locales(locale)
64
- end
52
+ protected
65
53
 
66
- def fetch_translations(locale)
67
- # only query if not already included with :include => translations
68
- record.translations.loaded? ? record.translations :
69
- record.translations.with_locales(Globalize.fallbacks(locale))
54
+ def type_cast(name, value)
55
+ if value.nil?
56
+ nil
57
+ elsif column = column_for_attribute(name)
58
+ column.type_cast(value)
59
+ else
60
+ value
70
61
  end
62
+ end
71
63
 
72
- def fetch_attribute(locale, name)
73
- translations = fetch_translations(locale)
74
- value, requested_locale = nil, locale
64
+ def column_for_attribute(name)
65
+ translation_class.columns_hash[name.to_s]
66
+ end
75
67
 
76
- Globalize.fallbacks(locale).each do |fallback|
77
- translation = translations.to_a.detect { |t| t.locale == fallback }
78
- value = translation && translation.send(name)
79
- locale = fallback && break if value
80
- end
68
+ def unserializable_attribute?(name, column)
69
+ column.text? && translation_class.serialized_attributes[name.to_s]
70
+ end
81
71
 
82
- set_metadata(value, :locale => locale, :requested_locale => requested_locale)
83
- value
84
- end
72
+ def fetch_attribute(locale, name)
73
+ translations ||= record.translations
74
+ translation = translations.detect{|t| t.locale == locale}
75
+ return translation && translation.send(name)
76
+ end
85
77
 
86
- def set_metadata(object, metadata)
87
- if object.respond_to?(:translation_metadata)
88
- object.translation_metadata.merge!(meta_data)
89
- end
90
- end
78
+ def set_metadata(object, metadata)
79
+ object.translation_metadata.merge!(meta_data) if object.respond_to?(:translation_metadata)
80
+ object
81
+ end
91
82
 
92
- def translation_metadata_accessor(object)
93
- return if obj.respond_to?(:translation_metadata)
94
- class << object; attr_accessor :translation_metadata end
95
- object.translation_metadata ||= {}
96
- end
83
+ def translation_metadata_accessor(object)
84
+ return if obj.respond_to?(:translation_metadata)
85
+ class << object; attr_accessor :translation_metadata end
86
+ object.translation_metadata ||= {}
87
+ end
97
88
  end
98
89
  end
99
90
  end
100
-
@@ -3,7 +3,7 @@
3
3
 
4
4
  module Globalize
5
5
  module ActiveRecord
6
- class Attributes < Hash
6
+ class Attributes < Hash # TODO: Think about using HashWithIndifferentAccess ?
7
7
  def [](locale)
8
8
  locale = locale.to_sym
9
9
  self[locale] = {} unless has_key?(locale)
@@ -19,6 +19,7 @@ module Globalize
19
19
  end
20
20
 
21
21
  def write(locale, name, value)
22
+ #raise 'z' if value.nil? # TODO
22
23
  self[locale][name.to_s] = value
23
24
  end
24
25
  end
@@ -4,7 +4,7 @@ module Globalize
4
4
  delegate :translated_locales, :set_translations_table_name, :to => :translation_class
5
5
 
6
6
  def with_locales(*locales)
7
- scoped & translation_class.with_locales(*locales)
7
+ scoped.merge(translation_class.with_locales(*locales))
8
8
  end
9
9
 
10
10
  def with_translations(*locales)
@@ -39,16 +39,18 @@ module Globalize
39
39
  end
40
40
 
41
41
  def translation_class
42
- klass = self.const_get(:Translation) rescue nil
43
- if(klass.nil? || (klass.class_name != (self.class_name + "Translation")))
44
- klass = self.const_set(:Translation, Class.new(Globalize::ActiveRecord::Translation))
45
- end
42
+ @translation_class ||= begin
43
+ klass = self.const_get(:Translation) rescue nil
44
+ if klass.nil? || klass.class_name != (self.class_name + "Translation")
45
+ klass = self.const_set(:Translation, Class.new(Globalize::ActiveRecord::Translation))
46
+ end
46
47
 
47
- if klass.table_name == 'translations'
48
- klass.set_table_name(translation_options[:table_name])
49
- klass.belongs_to name.underscore.gsub('/', '_')
48
+ if klass.table_name == 'translations'
49
+ klass.set_table_name(translation_options[:table_name])
50
+ klass.belongs_to name.underscore.gsub('/', '_')
51
+ end
52
+ klass
50
53
  end
51
- klass
52
54
  end
53
55
 
54
56
  def translations_table_name
@@ -59,30 +61,64 @@ module Globalize
59
61
  "#{translation_class.table_name}.#{name}"
60
62
  end
61
63
 
62
- def respond_to?(method, *args, &block)
63
- method.to_s =~ /^find_by_(\w+)$/ && translated?($1.to_sym) || super
64
+ if RUBY_VERSION < '1.9'
65
+ def respond_to?(method_id, *args, &block)
66
+ supported_on_missing?(method_id) || super
67
+ end
68
+ else
69
+ def respond_to_missing?(method_id, include_private = false)
70
+ supported_on_missing?(method_id) || super
71
+ end
64
72
  end
65
73
 
66
- def method_missing(method, *args)
67
- if method.to_s =~ /^find_(first_|)by_(\w+)$/ && translated?($2.to_sym)
68
- result = with_translated_attribute($2, args.first)
69
- $1 == 'first_' ? result.first : result.all
70
- else
71
- super
74
+ def supported_on_missing?(method_id)
75
+ return super unless RUBY_VERSION < '1.9' || respond_to?(:translated_attribute_names)
76
+ match = ::ActiveRecord::DynamicFinderMatch.match(method_id) || ::ActiveRecord::DynamicScopeMatch.match(method_id)
77
+ return false if match.nil?
78
+
79
+ attribute_names = match.attribute_names.map(&:to_sym)
80
+ translated_attributes = attribute_names & translated_attribute_names
81
+ return false if translated_attributes.empty?
82
+
83
+ untranslated_attributes = attribute_names - translated_attributes
84
+ return false if untranslated_attributes.any?{|unt| ! respond_to?(:"scoped_by_#{unt}")}
85
+ return [match, attribute_names, translated_attributes, untranslated_attributes]
86
+ end
87
+
88
+ def method_missing(method_id, *arguments, &block)
89
+ match, attribute_names, translated_attributes, untranslated_attributes = supported_on_missing?(method_id)
90
+ return super unless match
91
+
92
+ scope = scoped
93
+
94
+ translated_attributes.each do |attr|
95
+ scope = scope.with_translated_attribute(attr, arguments[attribute_names.index(attr)])
72
96
  end
97
+
98
+ untranslated_attributes.each do |unt|
99
+ index = attribute_names.index(unt)
100
+ raise StandarError unless index
101
+ scope = scope.send(:"scoped_by_#{unt}", arguments[index])
102
+ end
103
+
104
+ return scope.send(match.finder) if match.is_a?(::ActiveRecord::DynamicFinderMatch)
105
+ return scope
73
106
  end
74
107
 
75
- protected
108
+ protected
76
109
 
77
- def translated_attr_accessor(name)
78
- define_method(:"#{name}=") do |value|
79
- write_attribute(name, value)
80
- end
81
- define_method(name) do |*args|
82
- read_attribute(name, {:locale => args.first})
83
- end
84
- alias_method :"#{name}_before_type_cast", name
110
+ def translated_attr_accessor(name)
111
+ define_method(:"#{name}=") do |value|
112
+ write_attribute(name, value)
85
113
  end
114
+ define_method(name) do |*args|
115
+ read_attribute(name, {:locale => args.first})
116
+ end
117
+ alias_method :"#{name}_before_type_cast", name
118
+ end
119
+
86
120
  end
121
+
87
122
  end
88
- end
123
+
124
+ end
@@ -24,9 +24,7 @@ module Globalize
24
24
  end
25
25
 
26
26
  def write_attribute(name, value, options = {})
27
- # Make sure that we return some value as some methods might
28
- # rely on the data
29
- return_value = super(name, value)
27
+ # raise 'y' if value.nil? # TODO.
30
28
 
31
29
  if translated?(name)
32
30
  # Deprecate old use of locale
@@ -35,9 +33,11 @@ module Globalize
35
33
  options = {:locale => options}
36
34
  end
37
35
  options = {:locale => nil}.merge(options)
38
- return_value = globalize.write(options[:locale] || Globalize.locale, name, value)
36
+ attribute_will_change! name.to_s
37
+ globalize.write(options[:locale] || Globalize.locale, name, value)
38
+ else
39
+ super(name, value)
39
40
  end
40
- return_value
41
41
  end
42
42
 
43
43
  def read_attribute(name, options = {})
@@ -93,20 +93,47 @@ module Globalize
93
93
  super(options)
94
94
  end
95
95
 
96
- protected
96
+ def clone
97
+ obj = super
98
+ return obj unless respond_to?(:translated_attribute_names)
97
99
 
98
- def save_translations!
99
- globalize.save_translations!
100
+ obj.instance_variable_set(:@translations, nil) if new_record? # Reset the collection because of rails bug: http://pastie.org/1521874
101
+ obj.instance_variable_set(:@globalize, nil )
102
+ each_locale_and_translated_attribute do |locale, name|
103
+ obj.globalize.write(locale, name, globalize.fetch(locale, name) )
100
104
  end
101
105
 
102
- def with_given_locale(attributes, &block)
103
- attributes.symbolize_keys! if attributes.respond_to?(:symbolize_keys!)
104
- if locale = attributes.try(:delete, :locale)
105
- Globalize.with_locale(locale, &block)
106
- else
107
- yield
106
+ return obj
107
+ end
108
+
109
+ protected
110
+
111
+ def each_locale_and_translated_attribute
112
+ used_locales.each do |locale|
113
+ translated_attribute_names.each do |name|
114
+ yield locale, name
108
115
  end
109
116
  end
117
+ end
118
+
119
+ def used_locales
120
+ locales = globalize.stash.keys.concat(globalize.stash.keys).concat(translations.translated_locales)
121
+ locales.uniq!
122
+ locales
123
+ end
124
+
125
+ def save_translations!
126
+ globalize.save_translations!
127
+ end
128
+
129
+ def with_given_locale(attributes, &block)
130
+ attributes.symbolize_keys! if attributes.respond_to?(:symbolize_keys!)
131
+ if locale = attributes.try(:delete, :locale)
132
+ Globalize.with_locale(locale, &block)
133
+ else
134
+ yield
135
+ end
136
+ end
110
137
  end
111
138
  end
112
139
  end
@@ -3,7 +3,10 @@ module Globalize
3
3
  class Translation < ::ActiveRecord::Base
4
4
  class << self
5
5
  def with_locales(*locales)
6
- where(:locale => locales.flatten.map(&:to_s))
6
+ # Avoid using "IN" with SQL queries when only using one locale.
7
+ locales = locales.flatten.map(&:to_s)
8
+ locales = locales.first if locales.one?
9
+ where(:locale => locales)
7
10
  end
8
11
  alias with_locale with_locales
9
12
 
data/lib/globalize.rb CHANGED
@@ -18,11 +18,17 @@ module Globalize
18
18
  def with_locale(locale, &block)
19
19
  previous_locale = read_locale
20
20
  set_locale(locale)
21
- result = yield
21
+ result = yield(locale)
22
22
  set_locale(previous_locale)
23
23
  result
24
24
  end
25
25
 
26
+ def with_locales(*locales, &block)
27
+ locales.flatten.map do |locale|
28
+ with_locale(locale, &block)
29
+ end
30
+ end
31
+
26
32
  def fallbacks?
27
33
  I18n.respond_to?(:fallbacks)
28
34
  end
@@ -31,15 +37,15 @@ module Globalize
31
37
  fallbacks? ? I18n.fallbacks[locale] : [locale.to_sym]
32
38
  end
33
39
 
34
- protected
40
+ protected
35
41
 
36
- def read_locale
37
- Thread.current[:globalize_locale]
38
- end
42
+ def read_locale
43
+ Thread.current[:globalize_locale]
44
+ end
39
45
 
40
- def set_locale(locale)
41
- Thread.current[:globalize_locale] = locale
42
- end
46
+ def set_locale(locale)
47
+ Thread.current[:globalize_locale] = locale.to_sym rescue nil
48
+ end
43
49
  end
44
50
  end
45
51
 
@@ -1,3 +1,3 @@
1
1
  module Globalize3
2
- VERSION = '0.1.0.beta'
2
+ VERSION = '0.1.0.beta2'
3
3
  end
metadata CHANGED
@@ -1,14 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: globalize3
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31098185
5
4
  prerelease: 6
6
- segments:
7
- - 0
8
- - 1
9
- - 0
10
- - beta
11
- version: 0.1.0.beta
5
+ version: 0.1.0.beta2
12
6
  platform: ruby
13
7
  authors:
14
8
  - Sven Fuchs
@@ -19,7 +13,7 @@ autorequire:
19
13
  bindir: bin
20
14
  cert_chain: []
21
15
 
22
- date: 2011-01-12 00:00:00 +01:00
16
+ date: 2011-05-20 00:00:00 +12:00
23
17
  default_executable:
24
18
  dependencies:
25
19
  - !ruby/object:Gem::Dependency
@@ -30,11 +24,6 @@ dependencies:
30
24
  requirements:
31
25
  - - ">="
32
26
  - !ruby/object:Gem::Version
33
- hash: 7
34
- segments:
35
- - 3
36
- - 0
37
- - 0
38
27
  version: 3.0.0
39
28
  type: :runtime
40
29
  version_requirements: *id001
@@ -46,11 +35,6 @@ dependencies:
46
35
  requirements:
47
36
  - - ">="
48
37
  - !ruby/object:Gem::Version
49
- hash: 7
50
- segments:
51
- - 3
52
- - 0
53
- - 0
54
38
  version: 3.0.0
55
39
  type: :runtime
56
40
  version_requirements: *id002
@@ -62,11 +46,6 @@ dependencies:
62
46
  requirements:
63
47
  - - "="
64
48
  - !ruby/object:Gem::Version
65
- hash: 15
66
- segments:
67
- - 0
68
- - 5
69
- - 2
70
49
  version: 0.5.2
71
50
  type: :development
72
51
  version_requirements: *id003
@@ -78,9 +57,6 @@ dependencies:
78
57
  requirements:
79
58
  - - ">="
80
59
  - !ruby/object:Gem::Version
81
- hash: 3
82
- segments:
83
- - 0
84
60
  version: "0"
85
61
  type: :development
86
62
  version_requirements: *id004
@@ -92,9 +68,6 @@ dependencies:
92
68
  requirements:
93
69
  - - ">="
94
70
  - !ruby/object:Gem::Version
95
- hash: 3
96
- segments:
97
- - 0
98
71
  version: "0"
99
72
  type: :development
100
73
  version_requirements: *id005
@@ -106,23 +79,17 @@ dependencies:
106
79
  requirements:
107
80
  - - ">="
108
81
  - !ruby/object:Gem::Version
109
- hash: 3
110
- segments:
111
- - 0
112
82
  version: "0"
113
83
  type: :development
114
84
  version_requirements: *id006
115
85
  - !ruby/object:Gem::Dependency
116
- name: ruby-debug
86
+ name: ruby-debug19
117
87
  prerelease: false
118
88
  requirement: &id007 !ruby/object:Gem::Requirement
119
89
  none: false
120
90
  requirements:
121
91
  - - ">="
122
92
  - !ruby/object:Gem::Version
123
- hash: 3
124
- segments:
125
- - 0
126
93
  version: "0"
127
94
  type: :development
128
95
  version_requirements: *id007
@@ -134,9 +101,6 @@ dependencies:
134
101
  requirements:
135
102
  - - ">="
136
103
  - !ruby/object:Gem::Version
137
- hash: 3
138
- segments:
139
- - 0
140
104
  version: "0"
141
105
  type: :development
142
106
  version_requirements: *id008
@@ -186,25 +150,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
186
150
  requirements:
187
151
  - - ">="
188
152
  - !ruby/object:Gem::Version
189
- hash: 3
190
- segments:
191
- - 0
192
153
  version: "0"
193
154
  required_rubygems_version: !ruby/object:Gem::Requirement
194
155
  none: false
195
156
  requirements:
196
157
  - - ">"
197
158
  - !ruby/object:Gem::Version
198
- hash: 25
199
- segments:
200
- - 1
201
- - 3
202
- - 1
203
159
  version: 1.3.1
204
160
  requirements: []
205
161
 
206
162
  rubyforge_project: "[none]"
207
- rubygems_version: 1.4.2
163
+ rubygems_version: 1.6.2
208
164
  signing_key:
209
165
  specification_version: 3
210
166
  summary: "Rails I18n: de-facto standard library for ActiveRecord 3 model/data translation"