globalize 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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