globalize 3.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7415d0b0223d5ace130c535aaee60e36929a4c7d
4
+ data.tar.gz: b4b6553f95f6f662aab9036c96b66ad0d7cac875
5
+ SHA512:
6
+ metadata.gz: 79141074b2c0943e9af5d02a1cb2c44bee1394f061398fc338d762891799b0d952ebe3e1a0ae25911759e00afb66c52227f20cac4907fe6af472f82d39a21307
7
+ data.tar.gz: e4d92686bcbd19736730327ef01f478d179fa0c60229dc4b17e038e274e66216f30e69845d6b29d409c091a36ebe4bb29eca08dfb2b00fc1672ae5adf36b34d6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
data/Gemfile.lock ADDED
@@ -0,0 +1,87 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ globalize (3.0.0)
5
+ activemodel (>= 3.0.0)
6
+ activerecord (>= 3.0.0)
7
+ paper_trail (~> 2)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actionpack (3.2.15)
13
+ activemodel (= 3.2.15)
14
+ activesupport (= 3.2.15)
15
+ builder (~> 3.0.0)
16
+ erubis (~> 2.7.0)
17
+ journey (~> 1.0.4)
18
+ rack (~> 1.4.5)
19
+ rack-cache (~> 1.2)
20
+ rack-test (~> 0.6.1)
21
+ sprockets (~> 2.2.1)
22
+ activemodel (3.2.15)
23
+ activesupport (= 3.2.15)
24
+ builder (~> 3.0.0)
25
+ activerecord (3.2.15)
26
+ activemodel (= 3.2.15)
27
+ activesupport (= 3.2.15)
28
+ arel (~> 3.0.2)
29
+ tzinfo (~> 0.3.29)
30
+ activesupport (3.2.15)
31
+ i18n (~> 0.6, >= 0.6.4)
32
+ multi_json (~> 1.0)
33
+ arel (3.0.2)
34
+ builder (3.0.4)
35
+ database_cleaner (0.6.7)
36
+ erubis (2.7.0)
37
+ hike (1.2.3)
38
+ i18n (0.6.5)
39
+ journey (1.0.4)
40
+ json (1.8.1)
41
+ metaclass (0.0.1)
42
+ mocha (0.14.0)
43
+ metaclass (~> 0.0.1)
44
+ multi_json (1.8.2)
45
+ paper_trail (2.7.2)
46
+ activerecord (~> 3.0)
47
+ railties (~> 3.0)
48
+ pathname_local (0.0.2)
49
+ rack (1.4.5)
50
+ rack-cache (1.2)
51
+ rack (>= 0.4)
52
+ rack-ssl (1.3.3)
53
+ rack
54
+ rack-test (0.6.2)
55
+ rack (>= 1.0)
56
+ railties (3.2.15)
57
+ actionpack (= 3.2.15)
58
+ activesupport (= 3.2.15)
59
+ rack-ssl (~> 1.3.2)
60
+ rake (>= 0.8.7)
61
+ rdoc (~> 3.4)
62
+ thor (>= 0.14.6, < 2.0)
63
+ rake (10.1.0)
64
+ rdoc (3.12.2)
65
+ json (~> 1.4)
66
+ sprockets (2.2.2)
67
+ hike (~> 1.2)
68
+ multi_json (~> 1.0)
69
+ rack (~> 1.0)
70
+ tilt (~> 1.1, != 1.3.0)
71
+ sqlite3 (1.3.7)
72
+ test_declarative (0.0.5)
73
+ thor (0.18.1)
74
+ tilt (1.4.1)
75
+ tzinfo (0.3.38)
76
+
77
+ PLATFORMS
78
+ java
79
+ ruby
80
+
81
+ DEPENDENCIES
82
+ database_cleaner (~> 0.6.0)
83
+ globalize!
84
+ mocha
85
+ pathname_local
86
+ sqlite3
87
+ test_declarative
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2008, 2009, 2010 Sven Fuchs, Joshua Harvey, Clemens Kofler, John-Paul Bader
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rdoc/task'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Run all tests.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'Globalize'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
data/lib/globalize.rb ADDED
@@ -0,0 +1,80 @@
1
+ require 'active_record'
2
+ require 'patches/active_record/xml_attribute_serializer'
3
+ require 'patches/active_record/query_method'
4
+ require 'patches/active_record/uniqueness_validator'
5
+ require 'patches/active_record/relation'
6
+
7
+ module Globalize
8
+ autoload :ActiveRecord, 'globalize/active_record'
9
+ autoload :Versioning, 'globalize/versioning'
10
+ autoload :Interpolation, 'globalize/interpolation'
11
+
12
+ class << self
13
+ def locale
14
+ read_locale || I18n.locale
15
+ end
16
+
17
+ def locale=(locale)
18
+ set_locale(locale)
19
+ end
20
+
21
+ def with_locale(locale, &block)
22
+ previous_locale = read_locale
23
+ begin
24
+ set_locale(locale)
25
+ result = yield(locale)
26
+ ensure
27
+ set_locale(previous_locale)
28
+ end
29
+ result
30
+ end
31
+
32
+ def with_locales(*locales, &block)
33
+ locales.flatten.map do |locale|
34
+ with_locale(locale, &block)
35
+ end
36
+ end
37
+
38
+ def fallbacks=(locales)
39
+ set_fallbacks(locales)
40
+ end
41
+
42
+ def i18n_fallbacks?
43
+ I18n.respond_to?(:fallbacks)
44
+ end
45
+
46
+ def fallbacks(for_locale = self.locale)
47
+ read_fallbacks[for_locale] || default_fallbacks(for_locale)
48
+ end
49
+
50
+ def default_fallbacks(for_locale = self.locale)
51
+ i18n_fallbacks? ? I18n.fallbacks[for_locale] : [for_locale.to_sym]
52
+ end
53
+
54
+ protected
55
+
56
+ def read_locale
57
+ Thread.current[:globalize_locale]
58
+ end
59
+
60
+ def set_locale(locale)
61
+ Thread.current[:globalize_locale] = locale.try(:to_sym)
62
+ end
63
+
64
+ def read_fallbacks
65
+ Thread.current[:fallbacks] || HashWithIndifferentAccess.new
66
+ end
67
+
68
+ def set_fallbacks(locales)
69
+ fallback_hash = HashWithIndifferentAccess.new
70
+
71
+ locales.each do |key, value|
72
+ fallback_hash[key] = value.presence || [key]
73
+ end if locales.present?
74
+
75
+ Thread.current[:fallbacks] = fallback_hash
76
+ end
77
+ end
78
+ end
79
+
80
+ ActiveRecord::Base.extend(Globalize::ActiveRecord::ActMacro)
@@ -0,0 +1,12 @@
1
+ module Globalize
2
+ module ActiveRecord
3
+ autoload :ActMacro, 'globalize/active_record/act_macro'
4
+ autoload :Adapter, 'globalize/active_record/adapter'
5
+ autoload :Attributes, 'globalize/active_record/attributes'
6
+ autoload :ClassMethods, 'globalize/active_record/class_methods'
7
+ autoload :Exceptions, 'globalize/active_record/exceptions'
8
+ autoload :InstanceMethods, 'globalize/active_record/instance_methods'
9
+ autoload :Migration, 'globalize/active_record/migration'
10
+ autoload :Translation, 'globalize/active_record/translation'
11
+ end
12
+ end
@@ -0,0 +1,96 @@
1
+ module Globalize
2
+ module ActiveRecord
3
+ module ActMacro
4
+ def translates(*attr_names)
5
+
6
+ options = attr_names.extract_options!
7
+ setup_translates!(options) unless translates?
8
+
9
+ attr_names = attr_names.map(&:to_sym)
10
+ attr_names -= translated_attribute_names if defined?(translated_attribute_names)
11
+
12
+ if attr_names.present?
13
+ translation_class.instance_eval %{
14
+ attr_accessible :#{attr_names.join(', :')}
15
+ }
16
+
17
+ attr_names.each do |attr_name|
18
+ # Detect and apply serialization.
19
+ serializer = self.serialized_attributes[attr_name.to_s]
20
+ if serializer.present?
21
+ if defined?(::ActiveRecord::Coders::YAMLColumn) &&
22
+ serializer.is_a?(::ActiveRecord::Coders::YAMLColumn)
23
+
24
+ serializer = serializer.object_class
25
+ end
26
+
27
+ translation_class.send :serialize, attr_name, serializer
28
+ end
29
+
30
+ # Create accessors for the attribute.
31
+ translated_attr_accessor(attr_name)
32
+ translations_accessor(attr_name)
33
+
34
+ # Add attribute to the list.
35
+ self.translated_attribute_names << attr_name
36
+ end
37
+ end
38
+ end
39
+
40
+ def class_name
41
+ @class_name ||= begin
42
+ class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].downcase.camelize
43
+ pluralize_table_names ? class_name.singularize : class_name
44
+ end
45
+ end
46
+
47
+ def translates?
48
+ included_modules.include?(InstanceMethods)
49
+ end
50
+
51
+ protected
52
+ def setup_translates!(options)
53
+ options[:table_name] ||= "#{table_name.singularize}_translations"
54
+ options[:foreign_key] ||= class_name.foreign_key
55
+
56
+ class_attribute :translated_attribute_names, :translation_options, :fallbacks_for_empty_translations
57
+ self.translated_attribute_names = []
58
+ self.translation_options = options
59
+ self.fallbacks_for_empty_translations = options[:fallbacks_for_empty_translations]
60
+
61
+ include InstanceMethods
62
+ extend ClassMethods, Migration
63
+
64
+ translation_class.table_name = options[:table_name]
65
+
66
+ has_many :translations, :class_name => translation_class.name,
67
+ :foreign_key => options[:foreign_key],
68
+ :dependent => :destroy,
69
+ :extend => HasManyExtensions,
70
+ :autosave => false
71
+
72
+ after_create :save_translations!
73
+ after_update :save_translations!
74
+
75
+ if options[:versioning]
76
+ if options[:versioning].is_a?(Hash)
77
+ translation_class.versioned options[:versioning]
78
+ else
79
+ ::ActiveRecord::Base.extend(Globalize::Versioning::PaperTrail)
80
+
81
+ translation_class.has_paper_trail
82
+ delegate :version, :versions, :to => :translation
83
+ end
84
+ end
85
+
86
+ translation_class.instance_eval %{ attr_accessible :locale }
87
+ end
88
+ end
89
+
90
+ module HasManyExtensions
91
+ def find_or_initialize_by_locale(locale)
92
+ with_locale(locale.to_s).first || build(:locale => locale.to_s)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,111 @@
1
+ module Globalize
2
+ module ActiveRecord
3
+ class Adapter
4
+ # The cache caches attributes that already were looked up for read access.
5
+ # The stash keeps track of new or changed values that need to be saved.
6
+ attr_accessor :record, :stash, :translations
7
+ private :record=, :stash=
8
+
9
+ delegate :translation_class, :to => :'record.class'
10
+
11
+ def initialize(record)
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
20
+ end
21
+
22
+ def stash_contains?(locale, name)
23
+ stash.contains?(locale, name)
24
+ end
25
+
26
+ def fetch(locale, name)
27
+ record.globalize_fallbacks(locale).each do |fallback|
28
+ value = stash.contains?(fallback, name) ? fetch_stash(fallback, name) : fetch_attribute(fallback, name)
29
+
30
+ unless fallbacks_for?(value)
31
+ set_metadata(value, :locale => fallback, :requested_locale => locale)
32
+ return value
33
+ end
34
+ end
35
+
36
+ return nil
37
+ end
38
+
39
+ def write(locale, name, value)
40
+ stash.write(locale, name, value)
41
+ end
42
+
43
+ def save_translations!
44
+ existing_translations_by_locale = {}
45
+ record.translations.each do |t|
46
+ existing_translations_by_locale[t.locale.to_s] = t
47
+ end
48
+
49
+ stash.each do |locale, attrs|
50
+ if attrs.any?
51
+ locale_str = locale.to_s
52
+ translation = existing_translations_by_locale[locale_str] ||
53
+ record.translations.find_or_initialize_by_locale(locale_str)
54
+ attrs.each { |name, value| translation[name] = value }
55
+ translation.save!
56
+ end
57
+ end
58
+
59
+ reset
60
+ end
61
+
62
+ def reset
63
+ stash.clear
64
+ end
65
+
66
+ protected
67
+
68
+ def type_cast(name, value)
69
+ if value.nil?
70
+ nil
71
+ elsif column = column_for_attribute(name)
72
+ column.type_cast(value)
73
+ else
74
+ value
75
+ end
76
+ end
77
+
78
+ def column_for_attribute(name)
79
+ translation_class.columns_hash[name.to_s]
80
+ end
81
+
82
+ def unserializable_attribute?(name, column)
83
+ column.text? && translation_class.serialized_attributes[name.to_s]
84
+ end
85
+
86
+ def fetch_attribute(locale, name)
87
+ translation = record.translation_for(locale, false)
88
+ return translation && translation.send(name)
89
+ end
90
+
91
+ def set_metadata(object, metadata)
92
+ object.translation_metadata.merge!(metadata) if object.respond_to?(:translation_metadata)
93
+ object
94
+ end
95
+
96
+ def translation_metadata_accessor(object)
97
+ return if obj.respond_to?(:translation_metadata)
98
+ class << object; attr_accessor :translation_metadata end
99
+ object.translation_metadata ||= {}
100
+ end
101
+
102
+ def fallbacks_for?(object)
103
+ object.nil? || (fallbacks_for_empty_translations? && object.blank?)
104
+ end
105
+
106
+ def fallbacks_for_empty_translations?
107
+ record.fallbacks_for_empty_translations
108
+ end
109
+ end
110
+ end
111
+ end