wakari 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ .DS_Store
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
File without changes
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in wakari.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Valery Kvon
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Wakari
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'wakari'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install wakari
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,18 @@
1
+ class WakariController < ApplicationController
2
+
3
+ def self.controller_path
4
+ unless anonymous?
5
+ @controller_path ||= begin
6
+ model_name = name.sub(/Controller$/, '').singularize
7
+ model_name.constantize.model_name.collection.tap do |t|
8
+ t.instance_eval do
9
+ def include?(arg) # Rails hack! actionpack/lib/action_view/renderer/partial_renderer.rb
10
+ arg == "/" ? false : super
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,11 @@
1
+ require "wakari/version"
2
+
3
+ module Wakari
4
+ def self.load!
5
+ require 'wakari/engine'
6
+ require 'wakari/railtie'
7
+ end
8
+
9
+ end
10
+
11
+ Wakari.load!
@@ -0,0 +1,136 @@
1
+ require 'wakari/models/content'
2
+ require 'wakari/models/proxy'
3
+ require 'wakari/models/translation'
4
+ require 'wakari/models/meta'
5
+
6
+ module Wakari
7
+
8
+ class Bundle
9
+
10
+ attr_reader :content_class, :proxy_class, :translation_class, :meta_class, :options
11
+
12
+ def initialize(content_class, *args)
13
+ @content_class = content_class
14
+ @name = args.first
15
+ @options = args.extract_options!
16
+ end
17
+
18
+ def name
19
+ @name.to_s.underscore if @name
20
+ end
21
+
22
+ def translation_name
23
+ name||"translation"
24
+ end
25
+
26
+ def full_translation_name
27
+ [content_class.model_name.param_key, translation_name].join("_")
28
+ end
29
+
30
+ def translation_class
31
+ @translation_class ||= case options[:class_name]
32
+ when nil then
33
+ content_class.const_set(translation_name.classify, Class.new(Wakari::Translation::Base))
34
+ when String, Symbol then
35
+ options[:class_name].to_s.constantize
36
+ end
37
+ end
38
+
39
+ def meta_class
40
+ @meta_class ||= case options[:meta]
41
+ when :text then
42
+ translation_class.const_set("Meta", Class.new(Wakari::Meta::Text))
43
+ when :string then
44
+ translation_class.const_set("Meta", Class.new(Wakari::Meta::String))
45
+ when String, Symbol then
46
+ options[:meta].to_s.constantize
47
+ else
48
+ raise "#{content_class.name}: Meta model expected for multilang definition#{" :" + name if name }."
49
+ end
50
+ end
51
+
52
+ def proxy_class
53
+ if proxy_need?
54
+ @proxy_class ||= content_class.const_set("#{name.classify}Proxy", Class.new(Wakari::Proxy::Base))
55
+ end
56
+ end
57
+
58
+ def prepare!
59
+ meta_class.send(:include, Wakari::Meta::Model)
60
+ meta_class.send(:acts_as_meta_class, *meta_class_args)
61
+
62
+ translation_class.send(:include, Wakari::Translation::Model)
63
+ translation_class.send(:acts_as_translation_class, *translation_class_args)
64
+
65
+ content_class.send(:include, Wakari::Content::Model)
66
+ content_class.send(:acts_as_content_class, *content_class_args)
67
+
68
+ if proxy_class
69
+ proxy_class.send(:include, Wakari::Proxy::Model)
70
+ proxy_class.send(:acts_as_proxy, *proxy_class_args)
71
+ content_class.class_eval <<-EOV
72
+ attr_accessible :#{name}
73
+
74
+ def #{name}
75
+ #{proxy_class}.new(self)
76
+ end
77
+ def #{name}=(*args)
78
+ #{proxy_class}.new(self).write(*args)
79
+ end
80
+ EOV
81
+ else
82
+ content_class.send(:include, Wakari::Proxy::Model) unless content_class < Wakari::Proxy::Model
83
+ content_class.send(:acts_as_proxy, *proxy_class_args)
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def proxy_need?
90
+ name.present?
91
+ end
92
+
93
+ def association_name
94
+ translation_name.pluralize.to_sym
95
+ end
96
+
97
+ def full_association_name
98
+ full_translation_name.pluralize.to_sym
99
+ end
100
+
101
+ def translation_class_options
102
+ options
103
+ end
104
+
105
+ def translation_class_args
106
+ [content_class, association_name, meta_class, full_association_name, translation_class_options]
107
+ end
108
+
109
+ def meta_class_options
110
+ options
111
+ end
112
+
113
+ def meta_class_args
114
+ [translation_class, full_association_name, meta_class_options]
115
+ end
116
+
117
+ def proxy_class_options
118
+ options
119
+ end
120
+
121
+ def proxy_class_args
122
+ [translation_class, association_name, proxy_class_options]
123
+ end
124
+
125
+ def content_class_options
126
+ options
127
+ end
128
+
129
+ def content_class_args
130
+ [translation_class, association_name, content_class_options]
131
+ end
132
+
133
+ end
134
+
135
+
136
+ end
@@ -0,0 +1,16 @@
1
+ require 'wakari/controllers/controller'
2
+
3
+ module Wakari
4
+
5
+ module ActionControllerExtension
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,14 @@
1
+ module Wakari
2
+
3
+ module Controller
4
+ module Model
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+
9
+ end
10
+ end
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,4 @@
1
+ module Wakari #:nodoc:
2
+ class Engine < ::Rails::Engine #:nodoc:
3
+ end
4
+ end
@@ -0,0 +1,10 @@
1
+ module Wakari
2
+
3
+ module ActionViewExtension
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ end
8
+ end
9
+
10
+ end
@@ -0,0 +1,15 @@
1
+ require 'wakari/multilang'
2
+
3
+ module Wakari
4
+
5
+ module ActiveRecordExtension
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ class_eval do
10
+ include Wakari::Multilang
11
+ end
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,7 @@
1
+ require 'wakari/models/content/model'
2
+
3
+ module Wakari
4
+ module Content
5
+
6
+ end
7
+ end
@@ -0,0 +1,45 @@
1
+ module Wakari
2
+ module Content
3
+ module Model
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ def acts_as_content_class(translation_class, association_name, options)
12
+ has_many association_name, :class_name => translation_class.name, :inverse_of => :content, :order => :position, :autosave => true, :foreign_key => :content_id
13
+ default_scope { includes(association_name) }
14
+ end
15
+
16
+ def i18n_namespaced_scope(resource) #:nodoc:
17
+ :"#{self.i18n_scope}.#{resource}.#{self.model_name.i18n_key.to_s.gsub(/\//,".")}"
18
+ end
19
+
20
+ def i18n_default_scope(resource) #:nodoc:
21
+ :"#{self.i18n_scope}.#{resource}.#{self.model_name.i18n_key.to_s}"
22
+ end
23
+
24
+ def dom_class
25
+ model_name.param_key
26
+ end
27
+
28
+ end
29
+
30
+ def dom_id(prefix = nil)
31
+ [prefix, self.class.dom_class, to_key].compact.join("_")
32
+ end
33
+
34
+ def current_locale
35
+ I18n.locale.to_s
36
+ end
37
+
38
+ def current_lang
39
+ Gaigo::LANGS.get(current_locale)
40
+ end
41
+
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ require 'wakari/models/meta/model'
2
+ require 'wakari/models/meta/reference'
3
+
4
+ module Wakari
5
+ module Meta
6
+ class String < ActiveRecord::Base
7
+ self.table_name = "meta_strings"
8
+ attr_accessible :value
9
+ validates_presence_of :value
10
+ end
11
+
12
+ class Text < ActiveRecord::Base
13
+ self.table_name = "meta_texts"
14
+ attr_accessible :value
15
+ validates_presence_of :value
16
+ end
17
+
18
+ # class StringReference < ActiveRecord::Base
19
+ # self.table_name = "references"
20
+ # attr_accessible :meta_id, :reference_id
21
+ # include Meta::Reference
22
+ # end
23
+ #
24
+ # class TextReference < ActiveRecord::Base
25
+ # self.table_name = "references"
26
+ # attr_accessible :meta_id, :reference_id
27
+ # include Meta::Reference
28
+ # end
29
+
30
+ end
31
+ end
@@ -0,0 +1,22 @@
1
+ module Wakari
2
+ module Meta
3
+
4
+ module Model
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ end
9
+
10
+ module ClassMethods
11
+ def acts_as_meta_class(translation_class, full_association_name, options)
12
+ has_many full_association_name, :class_name => translation_class.name, :inverse_of => :meta, :order => :created_at, :foreign_key => :meta_id
13
+ end
14
+ end
15
+
16
+ def to_s
17
+ value
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ module Wakari
2
+ module Meta
3
+
4
+ module Reference
5
+ module Model
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ end
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,42 @@
1
+ require 'wakari/models/proxy/model'
2
+
3
+ module Wakari
4
+ module Proxy
5
+ class Base
6
+ #include ActiveModel::AttributeMethods
7
+ include ActiveModel::MassAssignmentSecurity
8
+ attr_reader :content
9
+ delegate :current_locale, :current_lang, :to => :content
10
+ delegate :==, :nil?, :present?, :to => :current_translation
11
+
12
+ extend ActiveModel::Naming
13
+
14
+ def initialize(content)
15
+ @content = content
16
+ end
17
+
18
+ # def translations
19
+ # _translations_proc.call(content)
20
+ # end
21
+
22
+ def write(params={})
23
+ detect_current_translation.tap do |t|
24
+ t.attributes = params.delete_if {|k| k.to_s == "locale"}
25
+ end
26
+ end
27
+
28
+ def inspect
29
+ translations.inspect
30
+ end
31
+
32
+ def method_missing(*args, &block)
33
+ current_translation.send(*args, &block)
34
+ end
35
+
36
+ def dom_id(prefix = nil)
37
+ [prefix, content.dom_id, translations.klass.dom_class].compact.join("_")
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,113 @@
1
+ require 'wakari/models/support/errors'
2
+
3
+ module Wakari
4
+ module Proxy
5
+ module Model
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ end
10
+
11
+ module ClassMethods
12
+ def acts_as_proxy(translation_class, association_name, options)
13
+ lang_methods = translation_class._locales.collect do |lang|
14
+ method = lang.to_method
15
+ class_eval <<-EOV
16
+ def #{method}
17
+ translation?(\"#{lang.code}\")
18
+ end
19
+ def #{method}=(params={})
20
+ detect_translation(\"#{lang.code}\").tap do |t|
21
+ t.attributes = params.delete_if {|k| k.to_s == \"locale\"}
22
+ end
23
+ end
24
+ EOV
25
+ method
26
+ end
27
+ attr_accessible *lang_methods
28
+ delegate *translation_class._meta_attributes, :to => :current_translation, :allow_nil => true
29
+ delegate *translation_class._meta_attributes.collect {|attribute| "#{attribute}="}, :to => :detect_current_translation, :allow_nil => true
30
+
31
+ if self < Wakari::Proxy::Base
32
+ define_method :translations do |*args|
33
+ content.send(association_name, *args)
34
+ end
35
+ end
36
+
37
+ end
38
+ end
39
+
40
+ def translations_attributes
41
+ Hash[translations.map do |t|
42
+ if (lang = t.lang) && (attributes = t.meta_attributes).present?
43
+ [lang.to_method, attributes]
44
+ end
45
+ end.compact]
46
+ end
47
+
48
+ def possible_langs
49
+ translations.klass._locales
50
+ end
51
+
52
+ def used_langs
53
+ translations.map {|t| t.lang}
54
+ end
55
+
56
+ def available_langs
57
+ possible_langs - used_langs
58
+ end
59
+
60
+ def default_translation
61
+ translations.min_by {|t| t.position}
62
+ end
63
+
64
+ def translation(locale)
65
+ find_translation(:locale => locale)
66
+ end
67
+
68
+ def translation?(locale)
69
+ begin
70
+ translation(locale)
71
+ rescue TranslationNotFound
72
+ nil
73
+ end
74
+ end
75
+
76
+ def detect_translation(locale)
77
+ find_or_build_translation(:locale => locale)
78
+ end
79
+
80
+ def current_translation
81
+ translation?(current_locale)||translations.first
82
+ end
83
+
84
+ def detect_current_translation
85
+ detect_translation(current_locale)
86
+ end
87
+
88
+ def to_s(locale = nil)
89
+ (locale ? translation?(locale) : current_translation).try(:to_s)
90
+ end
91
+
92
+ private
93
+
94
+ def build_translation(params = {})
95
+ translations.build(params)
96
+ end
97
+
98
+ def find_or_build_translation(params = {})
99
+ begin
100
+ find_translation(params)
101
+ rescue TranslationNotFound
102
+ build_translation(params)
103
+ end
104
+ end
105
+
106
+ def find_translation(params = {})
107
+ translations.find {|t| t.match?(params)} || raise(TranslationNotFound, params)
108
+ end
109
+
110
+ end
111
+
112
+ end
113
+ end
@@ -0,0 +1,4 @@
1
+ module Wakari
2
+ class TranslationNotFound < StandardError
3
+ end
4
+ end
@@ -0,0 +1,53 @@
1
+ module Wakari
2
+ module Support
3
+ module Naming
4
+ extend ActiveSupport::Concern
5
+
6
+ class Name < ActiveModel::Name
7
+ attr_reader :parent_class
8
+
9
+ def initialize(parent_class, klass, namespace = nil, name = nil)
10
+ super(klass, namespace, name)
11
+ @parent_class = parent_class
12
+ @clear_name = (Rails.version <= "3.2.8" ? (name||klass.name) : @name).sub(/^#{parent_class.name}\W*/,'')
13
+ @singular = _singularize(@clear_name)
14
+ @plural = ActiveSupport::Inflector.pluralize(@singular)
15
+ @element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(@clear_name))
16
+ @collection = @parent_class.model_name.collection + "/" + ActiveSupport::Inflector.tableize(@clear_name)
17
+ @param_key = (namespace ? _singularize(@unnamespaced) : @singular)
18
+ @i18n_key = (@parent_class.model_name.i18n_key.to_s + "/" + @clear_name.underscore).to_sym
19
+ @route_key = (namespace ? ActiveSupport::Inflector.pluralize(@param_key) : @plural.dup)
20
+ @singular_route_key = ActiveSupport::Inflector.singularize(@route_key)
21
+ @route_key << "_index" if @plural == @singular
22
+ end
23
+
24
+ def human(options = {})
25
+ try_human(options)
26
+ end
27
+
28
+ end
29
+
30
+ module ClassMethods
31
+ def parent_class
32
+ self.name.split("::")[0..-2].join("::").constantize
33
+ end
34
+
35
+ def _to_partial_path #:nodoc:
36
+ @_to_partial_path ||= begin
37
+ "#{model_name.collection}/#{model_name.element}".freeze
38
+ end
39
+ end
40
+
41
+ def model_name
42
+ @_model_name ||= begin
43
+ namespace = self.parents.detect do |n|
44
+ n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
45
+ end
46
+ Name.new(parent_class, self, namespace)
47
+ end
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,12 @@
1
+ require 'wakari/models/translation/model'
2
+
3
+ module Wakari
4
+ module Translation
5
+
6
+ class Base < ActiveRecord::Base
7
+ self.table_name = "translations"
8
+ end
9
+
10
+ end
11
+
12
+ end
@@ -0,0 +1,223 @@
1
+ require 'wakari/models/support/naming'
2
+
3
+ module Wakari
4
+ module Translation
5
+
6
+ module Model
7
+ extend ActiveSupport::Concern
8
+ include Wakari::Support::Naming
9
+
10
+ included do
11
+ class_attribute :_meta_attributes unless defined?(_meta_attributes)
12
+
13
+ validates_presence_of :locale
14
+ validates_uniqueness_of :locale, :scope => [:type, :content_id]
15
+ before_save :commit_meta
16
+ after_destroy :clear_meta
17
+ validate do
18
+ unless meta_valid?
19
+ template_meta.errors.messages.each do |attribute, suberrors|
20
+ suberrors.each do |suberror|
21
+ errors.add(attribute, suberror)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ after_initialize do
27
+ template_meta
28
+ end
29
+ acts_as_list :scope => [:type, :content_id]
30
+ default_scope { includes(:meta) }
31
+ end
32
+
33
+ module ClassMethods
34
+
35
+ def dom_class
36
+ model_name.element
37
+ end
38
+
39
+ def acts_as_translation_class(content_class, association_name, meta_class, full_association_name, options)
40
+ has_locale! *Array.wrap(options[:locales])#, :accessible => false
41
+
42
+ belongs_to :content, :class_name => content_class.name, :inverse_of => association_name, :counter_cache => :"#{association_name}_count"
43
+ belongs_to :meta, :class_name => meta_class.name, :inverse_of => full_association_name, :counter_cache => :wakari_used
44
+
45
+ self._meta_attributes =
46
+ if meta_class < Wakari::Meta::Text || meta_class < Wakari::Meta::String
47
+ [:value]
48
+ else
49
+ Array.wrap(options[:attributes]).map {|a| a.to_sym}
50
+ end
51
+
52
+ attr_accessible *_meta_attributes, :content_id, :meta_id, :_destroy, :position
53
+ delegate *_meta_attributes, :to_s, :to => "(@_template_meta||meta)"
54
+ delegate *_meta_attributes.collect {|attribute| "#{attribute}="}, :to => :template_meta
55
+
56
+ (class << self; self; end).instance_eval do
57
+ define_method :i18n_inherited_namespaced_scope do |resource| #:nodoc:
58
+ :"#{content_class.i18n_namespaced_scope(resource)}.#{model_name.element}"
59
+ end
60
+
61
+ define_method :i18n_inherited_default_scope do |resource| #:nodoc:
62
+ :"#{content_class.i18n_default_scope(resource)}.#{model_name.element}"
63
+ end
64
+ end
65
+
66
+ define_method :stack do
67
+ content.send(association_name)
68
+ end
69
+
70
+ end
71
+
72
+ def try_human_attribute_name(attribute, options = {})
73
+ super(attribute, options) do |defaults|
74
+ defaults << :"#{i18n_inherited_namespaced_scope(:attributes)}.#{attribute}" ## added
75
+ defaults << :"#{i18n_inherited_default_scope(:attributes)}.#{attribute}" ## added
76
+ end
77
+ end
78
+
79
+ def human_attribute_name(attribute, options = {})
80
+ try_human_attribute_name(attribute, options)
81
+ end
82
+
83
+ end
84
+
85
+ def dom_id(prefix = nil)
86
+ [prefix, content.dom_id, self.class.dom_class, locale].compact.join("_")
87
+ end
88
+
89
+ def _destroy=(value)
90
+ case value
91
+ when 1, '1', true, 'true' then
92
+ mark_for_destruction
93
+ end
94
+ end
95
+
96
+ def siblings
97
+ stack - [self]
98
+ end
99
+
100
+ def meta_counter
101
+ counter = association(:meta).options[:counter_cache]
102
+ counter = self.class.model_name.plural + "_count" if counter == true
103
+ meta.send(counter) if counter
104
+ end
105
+
106
+ def only_once_used_meta?
107
+ meta_counter && meta_counter <= 1
108
+ end
109
+
110
+ def changed?
111
+ meta_changed? || super
112
+ end
113
+
114
+ def meta_changed?
115
+ eval(_meta_attributes.map {|a| "template_meta.send(:#{a}) != meta.send(:#{a})"}.join(" || ")) ## content changed?
116
+ end
117
+
118
+ def meta_valid?
119
+ template_meta.valid?
120
+ end
121
+
122
+ def match?(params = {})
123
+ m = params.map {|key, value| send(key) == (value.is_a?(Symbol) ? value.to_s : value)}
124
+ (m.include?(false) || m.blank?) ? false : true
125
+ end
126
+
127
+ def meta_attributes
128
+ Hash[_meta_attributes.map {|attr| value = send(attr); [attr.to_s, value] if value}.compact]
129
+ end
130
+
131
+ def lang
132
+ Gaigo::LANGS.get(locale)
133
+ end
134
+
135
+ def to_param
136
+ locale
137
+ end
138
+
139
+ private
140
+
141
+ def template_meta
142
+ @_template_meta ||= meta ? meta.dup : build_meta.dup
143
+ end
144
+
145
+ def clear_meta
146
+ if only_once_used_meta?
147
+ destroy_meta
148
+ end
149
+ end
150
+
151
+ def commit_meta
152
+ if meta_changed? ## writer attributes touched
153
+ attributes = extract_attributes(template_meta)
154
+ if meta.persisted?
155
+ if only_once_used_meta?
156
+ if exists_meta?(attributes)
157
+ destroy_meta
158
+ attach_or_create_meta(attributes)
159
+ else
160
+ update_meta(attributes)
161
+ end
162
+ else
163
+ attach_or_create_meta(attributes)
164
+ end
165
+ else
166
+ attach_or_create_meta(attributes)
167
+ end
168
+ end
169
+ end
170
+
171
+ def extract_attributes(object)
172
+ object.attributes.delete_if {|a| !a.to_sym.in?(_meta_attributes)}
173
+ end
174
+
175
+ def destroy_meta
176
+ begin
177
+ meta.destroy
178
+ puts "Translation '#{locale}': PERSISTED META DESTROYED!"
179
+ rescue ActiveRecord::StaleObjectError
180
+ meta.reload
181
+ commit_meta
182
+ end
183
+ end
184
+
185
+ def update_meta(attributes = {})
186
+ begin
187
+ meta.update_attributes(attributes)
188
+ puts "Translation '#{locale}': PERSISTED META UPDATED!"
189
+ rescue ActiveRecord::StaleObjectError
190
+ meta.reload
191
+ commit_meta
192
+ end
193
+ end
194
+
195
+ def find_existed_meta(attributes = {})
196
+ association(:meta).klass.where(attributes).limit(1).first
197
+ end
198
+
199
+ def create_new_meta(attributes = {})
200
+ create_meta(attributes).tap do |record|
201
+ record.send(:increment_lock) # Rails BUG! Counter caching process increments lock version in the DB table,
202
+ # but not in the associated object. So saving raises ActiveRecord::StaleObjectError.
203
+ end
204
+ end
205
+
206
+ def exists_meta?(attributes = {})
207
+ association(:meta).klass.exists?(attributes)
208
+ end
209
+
210
+ def attach_or_create_meta(attributes = {})
211
+ if existed = find_existed_meta(attributes)
212
+ self.meta = existed
213
+ puts "Translation '#{locale}': EXISTED META USED!"
214
+ else
215
+ self.meta = create_new_meta(attributes)
216
+ puts "Translation '#{locale}': NEW META CREATED!"
217
+ end
218
+ end
219
+
220
+ end
221
+ end
222
+
223
+ end
@@ -0,0 +1,14 @@
1
+ require 'wakari/bundle'
2
+
3
+ module Wakari
4
+ module Multilang
5
+
6
+ def multilang(*args, &block)
7
+ bundle = Bundle.new(self, *args)
8
+ bundle.prepare!
9
+ yield bundle if block_given?
10
+ end
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,20 @@
1
+ require 'rails'
2
+
3
+ module Wakari
4
+ class Railtie < ::Rails::Railtie
5
+ config.before_initialize do
6
+ ActiveSupport.on_load :active_record do
7
+ require 'wakari/models/active_record_extension'
8
+ include Wakari::ActiveRecordExtension
9
+ end
10
+ ActiveSupport.on_load :action_controller do
11
+ require 'wakari/controllers/action_controller_extension'
12
+ include Wakari::ActionControllerExtension
13
+ end
14
+ ActiveSupport.on_load :action_view do
15
+ require 'wakari/helpers/action_view_extension'
16
+ include Wakari::ActionViewExtension
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module Wakari
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wakari/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "wakari"
8
+ gem.version = Wakari::VERSION
9
+ gem.authors = ["Valery Kvon"]
10
+ gem.email = ["addagger@gmail.com"]
11
+ gem.homepage = %q{http://vkvon.ru/projects/wakari}
12
+ gem.description = %q{Add translations for models}
13
+ gem.summary = %q{Multilang assets for Rails}
14
+
15
+ gem.add_development_dependency "gaigo"
16
+ gem.add_development_dependency "acts_as_list"
17
+ gem.rubyforge_project = "wakari"
18
+
19
+ gem.files = `git ls-files`.split($/)
20
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
21
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
22
+ gem.require_paths = ["lib"]
23
+ gem.licenses = ['MIT']
24
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wakari
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Valery Kvon
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-31 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: gaigo
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: acts_as_list
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Add translations for models
47
+ email:
48
+ - addagger@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - CHANGELOG
55
+ - Gemfile
56
+ - LICENSE.txt
57
+ - README.md
58
+ - Rakefile
59
+ - app/controllers/wakari_controller.rb
60
+ - lib/wakari.rb
61
+ - lib/wakari/bundle.rb
62
+ - lib/wakari/controllers/action_controller_extension.rb
63
+ - lib/wakari/controllers/controller.rb
64
+ - lib/wakari/engine.rb
65
+ - lib/wakari/helpers/action_view_extension.rb
66
+ - lib/wakari/models/active_record_extension.rb
67
+ - lib/wakari/models/content.rb
68
+ - lib/wakari/models/content/model.rb
69
+ - lib/wakari/models/meta.rb
70
+ - lib/wakari/models/meta/model.rb
71
+ - lib/wakari/models/meta/reference.rb
72
+ - lib/wakari/models/proxy.rb
73
+ - lib/wakari/models/proxy/model.rb
74
+ - lib/wakari/models/support/errors.rb
75
+ - lib/wakari/models/support/naming.rb
76
+ - lib/wakari/models/translation.rb
77
+ - lib/wakari/models/translation/model.rb
78
+ - lib/wakari/multilang.rb
79
+ - lib/wakari/railtie.rb
80
+ - lib/wakari/version.rb
81
+ - wakari.gemspec
82
+ homepage: http://vkvon.ru/projects/wakari
83
+ licenses:
84
+ - MIT
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubyforge_project: wakari
103
+ rubygems_version: 1.8.24
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: Multilang assets for Rails
107
+ test_files: []