trasto 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,26 @@
1
+ *.sassc
2
+ .sass-cache
3
+ capybara-*.html
4
+ .rspec
5
+ **.orig
6
+ rerun.txt
7
+ pickle-email-*.html
8
+ *.gem
9
+ *.rbc
10
+ .bundle
11
+ .config
12
+ .yardoc
13
+ Gemfile.lock
14
+ InstalledFiles
15
+ _yardoc
16
+ coverage
17
+ doc/
18
+ lib/bundler/man
19
+ pkg
20
+ rdoc
21
+ spec/reports
22
+ spec/tmp
23
+ coverage
24
+ test/tmp
25
+ test/version_tmp
26
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in trasto.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Morton Jonuschat
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,84 @@
1
+ # Trasto
2
+
3
+ [![Build Status](https://secure.travis-ci.org/yabawock/trasto.png)](http://travis-ci.org/yabawock/trasto)
4
+
5
+ Translatable columns for Rails 3, directly stored in a postgres hstore in the model table.
6
+
7
+ Inspired by Barsoom's [traco](https://github.com/barsoom/traco/).
8
+
9
+ To store translations outside the model, see Sven Fuchs' [globalize3](https://github.com/svenfuchs/globalize3).
10
+
11
+ ## Usage
12
+
13
+ Say you want `Post#title` and `Post#body` to support both English and Swedish values.
14
+
15
+ Write a migration to get hstore database columns with i18n suffixes, e.g. `title_i18n` and `body_i18n`, like:
16
+
17
+ class CreatePosts < ActiveRecord::Migration
18
+ def change
19
+ create_table :posts do |t|
20
+ t.hstore :title_i18n
21
+ t.hstore :body_i18n
22
+
23
+ t.timestamps
24
+ end
25
+ end
26
+ end
27
+
28
+ Don't create `title` or `body` columns without the `_i18n` suffix, Trasto will define a method with that name.
29
+
30
+ Declare these columns in the model:
31
+
32
+ class Post < ActiveRecord::Base
33
+ translates :title, :body
34
+ end
35
+
36
+ You can still use your accessors for `title_i18n` and `title_i18=` in forms, validations and other code, but you also get:
37
+
38
+ `#title`: Shows the title in the current locale. If blank, falls back to default locale, then to any locale.
39
+
40
+ `#title=`: Assigns the title to the column for the current locale, if present.
41
+
42
+ `.locales_for_column(:title)`: Returns an array like `[:de, :en]` sorted with default locale first and then all currently available locals sorted alphabetically.
43
+
44
+ ## Installation
45
+
46
+ Add this to your `Gemfile` if you use Bundler 1.1+:
47
+
48
+ gem 'traco'
49
+
50
+ Then run
51
+
52
+ bundle install
53
+
54
+ to install it.
55
+
56
+
57
+ ## Running the tests
58
+
59
+ bundle
60
+ rake
61
+
62
+ ## Credits and license
63
+
64
+ By [Morton Jonuschat](https://github.com/yabawock) under the MIT license:
65
+
66
+ > Copyright (c) 2012 Morton Jonuschat
67
+ >
68
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
69
+ > of this software and associated documentation files (the "Software"), to deal
70
+ > in the Software without restriction, including without limitation the rights
71
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
72
+ > copies of the Software, and to permit persons to whom the Software is
73
+ > furnished to do so, subject to the following conditions:
74
+ >
75
+ > The above copyright notice and this permission notice shall be included in
76
+ > all copies or substantial portions of the Software.
77
+ >
78
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
79
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
80
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
81
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
82
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
83
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
84
+ > THE SOFTWARE.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,4 @@
1
+ require "trasto/version"
2
+ require "trasto/translates"
3
+ require "trasto/class_methods"
4
+ require "trasto/instance_methods"
@@ -0,0 +1,15 @@
1
+ module Trasto
2
+ module ClassMethods
3
+
4
+ private
5
+
6
+ def translates?(column)
7
+ translatable_columns.include?(column.to_sym)
8
+ end
9
+
10
+ def locale_name(locale)
11
+ I18n.t(locale, :scope => :"i18n.languages", :default => locale.to_s.upcase)
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,30 @@
1
+ module Trasto
2
+ module InstanceMethods
3
+
4
+ private
5
+
6
+ def read_localized_value(column)
7
+ locales_for_reading_column(column).each do |locale|
8
+ value = send("#{column}_i18n")[locale]
9
+ return value if value.present?
10
+ end
11
+ nil
12
+ end
13
+
14
+ def write_localized_value(column, value)
15
+ translations = send("#{column}_i18n") || {}
16
+ send("#{column}_i18n=", translations.merge({I18n.locale => value}))
17
+ end
18
+
19
+ def locales_for_reading_column(column)
20
+ send("#{column}_i18n").keys.sort_by { |locale|
21
+ case locale
22
+ when I18n.locale then "0"
23
+ when I18n.default_locale then "1"
24
+ else locale.to_s
25
+ end
26
+ }
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ module Trasto
2
+ module Translates
3
+ def translates(*columns)
4
+
5
+ extend Trasto::ClassMethods
6
+ include Trasto::InstanceMethods
7
+
8
+ # Don't overwrite values if running multiple times in the same class
9
+ # or in different classes of an inheritance chain.
10
+ unless respond_to?(:translatable_columns)
11
+ class_attribute :translatable_columns
12
+ self.translatable_columns = []
13
+ end
14
+
15
+ self.translatable_columns |= columns.map(&:to_sym)
16
+
17
+ columns.each do |column|
18
+
19
+ define_method(column) do
20
+ read_localized_value(column)
21
+ end
22
+
23
+ define_method("#{column}=") do |value|
24
+ write_localized_value(column, value)
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ ActiveRecord::Base.send :extend, Trasto::Translates
@@ -0,0 +1,3 @@
1
+ module Trasto
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,7 @@
1
+ de:
2
+ attributes:
3
+ title: "Titel"
4
+ i18n:
5
+ languages:
6
+ en: "English"
7
+ de: "Deutsch"
@@ -0,0 +1,5 @@
1
+ class Post < ActiveRecord::Base
2
+ end
3
+
4
+ class SubPost < Post
5
+ end
@@ -0,0 +1,32 @@
1
+ RSpec.configure do |config|
2
+ # Clear class state before each spec.
3
+ config.before(:each) do
4
+ Object.send(:remove_const, 'Post')
5
+ Object.send(:remove_const, 'SubPost')
6
+ load 'app/post.rb'
7
+ end
8
+ end
9
+
10
+ # Test against real ActiveRecord models.
11
+ # Very much based on the test setup in
12
+ # https://github.com/iain/translatable_columns/
13
+
14
+ require "active_record"
15
+ require "activerecord-postgres-hstore"
16
+ require "activerecord-postgres-hstore/activerecord"
17
+ require "app/post.rb"
18
+
19
+ ActiveRecord::Base.establish_connection :adapter => "postgresql", :database => "test"
20
+
21
+ silence_stream(STDOUT) do
22
+ ActiveRecord::Schema.define(:version => 0) do
23
+ execute "CREATE EXTENSION IF NOT EXISTS hstore"
24
+
25
+ create_table :posts, :force => true do |t|
26
+ t.hstore :title_i18n
27
+ t.hstore :body_i18n
28
+ end
29
+ end
30
+ end
31
+
32
+ I18n.load_path << "spec/app/de.yml"
@@ -0,0 +1,99 @@
1
+ require "spec_helper"
2
+ require "trasto"
3
+
4
+ describe ActiveRecord::Base, ".translates" do
5
+
6
+ it "should be available" do
7
+ Post.should respond_to :translates
8
+ end
9
+
10
+ it "should add functionality" do
11
+ Post.new.should_not respond_to :title
12
+ Post.translates :title
13
+ Post.new.should respond_to :title
14
+ end
15
+
16
+ it "should be possible to run more than once" do
17
+ Post.new.should_not respond_to :title, :body
18
+ Post.translates :title
19
+ Post.translates :body
20
+ Post.new.should respond_to :title, :body
21
+ end
22
+
23
+ it "inherits columns from the superclass" do
24
+ Post.translates :title
25
+ SubPost.translates :body
26
+ SubPost.new.should respond_to :title, :body
27
+ Post.new.should respond_to :title
28
+ Post.new.should_not respond_to :body
29
+ end
30
+
31
+ end
32
+
33
+ describe Post, ".translatable_columns" do
34
+
35
+ before do
36
+ Post.translates :title
37
+ end
38
+
39
+ it "should list the translatable columns" do
40
+ Post.translatable_columns.should == [ :title ]
41
+ end
42
+
43
+ end
44
+
45
+ describe Post, "#title" do
46
+
47
+ let(:post) { Post.new(:title_i18n => { :de => "Hallo", :en => "Hello", :sv => "Hej"} ) }
48
+
49
+ before do
50
+ Post.translates :title
51
+ I18n.locale = :en
52
+ I18n.default_locale = :de
53
+ end
54
+
55
+ it "should give the title in the current locale" do
56
+ post.title.should == "Hello"
57
+ end
58
+
59
+ it "should fall back to the default locale if locale has entry" do
60
+ I18n.locale = :ru
61
+ post.title.should == "Hallo"
62
+ end
63
+
64
+ it "should fall back to the default locale if blank" do
65
+ post.title_i18n[:en] = " "
66
+ post.title.should == "Hallo"
67
+ end
68
+
69
+ it "should fall back to any other locale if default locale is blank" do
70
+ post.title_i18n[:en] = " "
71
+ post.title_i18n[:de] = ""
72
+ post.title.should == "Hej"
73
+ end
74
+
75
+ it "should return nil if all are blank" do
76
+ post.title_i18n[:en] = " "
77
+ post.title_i18n[:de] = ""
78
+ post.title_i18n[:sv] = nil
79
+ post.title.should be_nil
80
+ end
81
+
82
+ end
83
+
84
+ describe Post, "#title=" do
85
+
86
+ before do
87
+ Post.translates :title
88
+ I18n.locale = :de
89
+ end
90
+
91
+ let(:post) { Post.new }
92
+
93
+ it "should assign in the current locale" do
94
+ post.title = "Hallo"
95
+ post.title.should == "Hallo"
96
+ post.title_i18n[:de].should == "Hallo"
97
+ end
98
+
99
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'trasto/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "trasto"
8
+ gem.version = Trasto::VERSION
9
+ gem.authors = ["Morton Jonuschat"]
10
+ gem.email = ["yabawock@gmail.com"]
11
+ gem.description = %q{Translatable columns for Rails 3, directly stored in a postgres hstore in the model table.}
12
+ gem.summary = %q{Make use of PostgreSQL hstore extension to store all column translations directly in the model table without adding tons of tables or columns}
13
+ gem.homepage = "https://github.com/yabawock/trasto"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "pg", "~> 0.10"
21
+ gem.add_dependency "activerecord-postgres-hstore", ">= 0.4.0"
22
+
23
+ gem.add_development_dependency "rake", "~> 0.9.2"
24
+ gem.add_development_dependency "rspec", "~> 2.11.0"
25
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trasto
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Morton Jonuschat
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: pg
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '0.10'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '0.10'
30
+ - !ruby/object:Gem::Dependency
31
+ name: activerecord-postgres-hstore
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 0.4.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 0.4.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.9.2
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.2
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 2.11.0
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 2.11.0
78
+ description: Translatable columns for Rails 3, directly stored in a postgres hstore
79
+ in the model table.
80
+ email:
81
+ - yabawock@gmail.com
82
+ executables: []
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - Gemfile
88
+ - LICENSE.txt
89
+ - README.md
90
+ - Rakefile
91
+ - lib/trasto.rb
92
+ - lib/trasto/class_methods.rb
93
+ - lib/trasto/instance_methods.rb
94
+ - lib/trasto/translates.rb
95
+ - lib/trasto/version.rb
96
+ - spec/app/de.yml
97
+ - spec/app/post.rb
98
+ - spec/spec_helper.rb
99
+ - spec/trasto_spec.rb
100
+ - trasto.gemspec
101
+ homepage: https://github.com/yabawock/trasto
102
+ licenses: []
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 1.8.23
122
+ signing_key:
123
+ specification_version: 3
124
+ summary: Make use of PostgreSQL hstore extension to store all column translations
125
+ directly in the model table without adding tons of tables or columns
126
+ test_files:
127
+ - spec/app/de.yml
128
+ - spec/app/post.rb
129
+ - spec/spec_helper.rb
130
+ - spec/trasto_spec.rb