wakari 0.0.2

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.
@@ -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: []