trasto 0.0.1

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,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