snusnu-dm-is-localizable 0.0.5
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.
- data/.document +5 -0
- data/.gitignore +23 -0
- data/CHANGELOG +183 -0
- data/LICENSE +20 -0
- data/README.textile +177 -0
- data/Rakefile +77 -0
- data/TODO +2 -0
- data/VERSION +1 -0
- data/dm-is-localizable.gemspec +82 -0
- data/features/dm-is-localizable.feature +9 -0
- data/features/step_definitions/dm-is-localizable_steps.rb +0 -0
- data/features/support/env.rb +4 -0
- data/lib/dm-is-localizable.rb +8 -0
- data/lib/dm-is-localizable/is/localizable.rb +89 -0
- data/lib/dm-is-localizable/storage/language.rb +15 -0
- data/lib/dm-is-localizable/storage/translation.rb +18 -0
- data/spec/fixtures/item.rb +12 -0
- data/spec/lib/rspec_tmbundle_support.rb +35 -0
- data/spec/shared/shared_examples_spec.rb +70 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +81 -0
- data/spec/unit/auto_migrate_spec.rb +13 -0
- data/spec/unit/class_level_api_spec.rb +159 -0
- data/spec/unit/instance_level_api_spec.rb +156 -0
- data/spec/unit/is_localizable_spec.rb +28 -0
- data/spec/unit/language_spec.rb +64 -0
- data/spec/unit/translation_spec.rb +16 -0
- data/tasks/changelog.rb +18 -0
- data/tasks/whitespace.rb +4 -0
- metadata +120 -0
data/TODO
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.5
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{dm-is-localizable}
|
5
|
+
s.version = "0.0.5"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Martin Gamsjaeger (snusnu)"]
|
9
|
+
s.date = %q{2009-05-18}
|
10
|
+
s.email = %q{gamsnjaga@gmail.com}
|
11
|
+
s.extra_rdoc_files = [
|
12
|
+
"LICENSE",
|
13
|
+
"README.textile"
|
14
|
+
]
|
15
|
+
s.files = [
|
16
|
+
".document",
|
17
|
+
".gitignore",
|
18
|
+
"CHANGELOG",
|
19
|
+
"LICENSE",
|
20
|
+
"README.textile",
|
21
|
+
"Rakefile",
|
22
|
+
"TODO",
|
23
|
+
"VERSION",
|
24
|
+
"dm-is-localizable.gemspec",
|
25
|
+
"features/dm-is-localizable.feature",
|
26
|
+
"features/step_definitions/dm-is-localizable_steps.rb",
|
27
|
+
"features/support/env.rb",
|
28
|
+
"lib/dm-is-localizable.rb",
|
29
|
+
"lib/dm-is-localizable/is/localizable.rb",
|
30
|
+
"lib/dm-is-localizable/storage/language.rb",
|
31
|
+
"lib/dm-is-localizable/storage/translation.rb",
|
32
|
+
"spec/fixtures/item.rb",
|
33
|
+
"spec/lib/rspec_tmbundle_support.rb",
|
34
|
+
"spec/shared/shared_examples_spec.rb",
|
35
|
+
"spec/spec.opts",
|
36
|
+
"spec/spec_helper.rb",
|
37
|
+
"spec/unit/auto_migrate_spec.rb",
|
38
|
+
"spec/unit/class_level_api_spec.rb",
|
39
|
+
"spec/unit/instance_level_api_spec.rb",
|
40
|
+
"spec/unit/is_localizable_spec.rb",
|
41
|
+
"spec/unit/language_spec.rb",
|
42
|
+
"spec/unit/translation_spec.rb",
|
43
|
+
"tasks/changelog.rb",
|
44
|
+
"tasks/whitespace.rb"
|
45
|
+
]
|
46
|
+
s.homepage = %q{http://github.com/snusnu/dm-is-localizable}
|
47
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
48
|
+
s.require_paths = ["lib"]
|
49
|
+
s.rubygems_version = %q{1.3.3}
|
50
|
+
s.summary = %q{Datamapper support for localization of content in multilanguage applications}
|
51
|
+
s.test_files = [
|
52
|
+
"spec/fixtures/item.rb",
|
53
|
+
"spec/lib/rspec_tmbundle_support.rb",
|
54
|
+
"spec/shared/shared_examples_spec.rb",
|
55
|
+
"spec/spec_helper.rb",
|
56
|
+
"spec/unit/auto_migrate_spec.rb",
|
57
|
+
"spec/unit/class_level_api_spec.rb",
|
58
|
+
"spec/unit/instance_level_api_spec.rb",
|
59
|
+
"spec/unit/is_localizable_spec.rb",
|
60
|
+
"spec/unit/language_spec.rb",
|
61
|
+
"spec/unit/translation_spec.rb"
|
62
|
+
]
|
63
|
+
|
64
|
+
if s.respond_to? :specification_version then
|
65
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
66
|
+
s.specification_version = 3
|
67
|
+
|
68
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
69
|
+
s.add_runtime_dependency(%q<dm-core>, [">= 0.9.11"])
|
70
|
+
s.add_runtime_dependency(%q<dm-is-remixable>, [">= 0.9.11"])
|
71
|
+
s.add_runtime_dependency(%q<dm-validations>, [">= 0.9.11"])
|
72
|
+
else
|
73
|
+
s.add_dependency(%q<dm-core>, [">= 0.9.11"])
|
74
|
+
s.add_dependency(%q<dm-is-remixable>, [">= 0.9.11"])
|
75
|
+
s.add_dependency(%q<dm-validations>, [">= 0.9.11"])
|
76
|
+
end
|
77
|
+
else
|
78
|
+
s.add_dependency(%q<dm-core>, [">= 0.9.11"])
|
79
|
+
s.add_dependency(%q<dm-is-remixable>, [">= 0.9.11"])
|
80
|
+
s.add_dependency(%q<dm-validations>, [">= 0.9.11"])
|
81
|
+
end
|
82
|
+
end
|
File without changes
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# Require plugin-files
|
2
|
+
dir = Pathname(__FILE__).dirname.expand_path / 'dm-is-localizable'
|
3
|
+
require dir / 'is' / 'localizable'
|
4
|
+
require dir / 'storage' / 'language'
|
5
|
+
require dir / 'storage' / 'translation'
|
6
|
+
|
7
|
+
# Include the plugin in Model
|
8
|
+
DataMapper::Model.append_extensions DataMapper::Is::Localizable
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Is
|
3
|
+
|
4
|
+
module Localizable
|
5
|
+
|
6
|
+
|
7
|
+
def is_localizable(options = {}, &block)
|
8
|
+
|
9
|
+
extend ClassMethods
|
10
|
+
include InstanceMethods
|
11
|
+
|
12
|
+
options = {
|
13
|
+
:as => nil,
|
14
|
+
:class_name => "#{self}Translation"
|
15
|
+
}.merge(options)
|
16
|
+
|
17
|
+
remixer_fk = Extlib::Inflection.foreign_key(self.name).to_sym
|
18
|
+
remixer = remixer_fk.to_s.gsub('_id', '').to_sym
|
19
|
+
remixee = Extlib::Inflection.tableize(options[:class_name]).to_sym
|
20
|
+
|
21
|
+
remix n, Translation, :as => options[:as], :class_name => options[:class_name]
|
22
|
+
|
23
|
+
@translation_class = Extlib::Inflection.constantize(options[:class_name])
|
24
|
+
class_inheritable_accessor :translation_class
|
25
|
+
|
26
|
+
enhance :translation, @translation_class do
|
27
|
+
|
28
|
+
property remixer_fk, Integer, :nullable => false, :unique_index => :unique_languages
|
29
|
+
property :language_id, Integer, :nullable => false, :unique_index => :unique_languages
|
30
|
+
|
31
|
+
belongs_to remixer
|
32
|
+
belongs_to :language
|
33
|
+
|
34
|
+
class_eval &block
|
35
|
+
|
36
|
+
validates_is_unique :language_id, :scope => remixer_fk
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
has n, :languages, :through => remixee
|
41
|
+
|
42
|
+
self.class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
43
|
+
alias :translations #{remixee}
|
44
|
+
EOS
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
module ClassMethods
|
49
|
+
|
50
|
+
# list all available languages for the localizable model
|
51
|
+
def available_languages
|
52
|
+
Language.all :id => translation_class.all.map { |t| t.language_id }.uniq
|
53
|
+
end
|
54
|
+
|
55
|
+
# the number of all available languages for the localizable model
|
56
|
+
def nr_of_available_languages
|
57
|
+
available_languages.size
|
58
|
+
end
|
59
|
+
|
60
|
+
# checks if all localizable resources are translated in all available languages
|
61
|
+
def translations_complete?
|
62
|
+
available_languages.size * all.size == translation_class.all.size
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
module InstanceMethods
|
68
|
+
|
69
|
+
# list all available languages for this instance
|
70
|
+
def available_languages
|
71
|
+
Language.all :id => translations.map { |t| t.language_id }.uniq
|
72
|
+
end
|
73
|
+
|
74
|
+
# the number of all available languages for this instance
|
75
|
+
def nr_of_available_languages
|
76
|
+
available_languages.size
|
77
|
+
end
|
78
|
+
|
79
|
+
# checks if this instance is translated into all available languages for this model
|
80
|
+
def translations_complete?
|
81
|
+
self.class.nr_of_available_languages == translations.size
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Language
|
2
|
+
|
3
|
+
include DataMapper::Resource
|
4
|
+
|
5
|
+
# properties
|
6
|
+
|
7
|
+
property :id, Serial
|
8
|
+
|
9
|
+
property :code, String, :nullable => false, :unique => true, :unique_index => true
|
10
|
+
property :name, String, :nullable => false
|
11
|
+
|
12
|
+
# locale string like 'en-US'
|
13
|
+
validates_format :code, :with => /^[a-z]{2}-[A-Z]{2}$/
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# -----------------------------------------------
|
2
|
+
# support for nice html output in rspec tmbundle
|
3
|
+
# -----------------------------------------------
|
4
|
+
|
5
|
+
module RSpecTmBundleHelpers
|
6
|
+
|
7
|
+
class TextmateRspecLogger < DataMapper::Logger
|
8
|
+
def prep_msg(message, level)
|
9
|
+
"#{super}<br />"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def with_dm_logger(level = :debug)
|
14
|
+
DataMapper.logger.level = level
|
15
|
+
yield
|
16
|
+
ensure
|
17
|
+
DataMapper.logger.level = :off
|
18
|
+
end
|
19
|
+
|
20
|
+
def print_call_stack(from = 2, to = nil, html = true)
|
21
|
+
(from..(to ? to : caller.length)).each do |idx|
|
22
|
+
p "[#{idx}]: #{caller[idx]}#{html ? '<br />' : ''}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def puth(html = nil)
|
27
|
+
print "#{h(html)}<br />"
|
28
|
+
end
|
29
|
+
|
30
|
+
ESCAPE_TABLE = { '&'=>'&', '<'=>'<', '>'=>'>', '"'=>'"', "'"=>''', }
|
31
|
+
def h(value)
|
32
|
+
value.to_s.gsub(/[&<>"]/) {|s| ESCAPE_TABLE[s] }
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe "all available_languages providers", :shared => true do
|
4
|
+
|
5
|
+
describe "with no translations" do
|
6
|
+
|
7
|
+
it "should return 0 languages" do
|
8
|
+
@provider.available_languages.size.should == 0
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "with 1 translation in 1 language" do
|
14
|
+
|
15
|
+
before :each do
|
16
|
+
@l = Language.create :code => 'en-US', :name => 'English'
|
17
|
+
@t = ItemTranslation.create :item => @item, :language => @l, :name => "Book", :desc => "Literature"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return 1 language" do
|
21
|
+
@provider.available_languages.size.should == 1
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return the right language" do
|
25
|
+
@provider.available_languages.first.should == @l
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "with 2 translations in 1 language" do
|
31
|
+
|
32
|
+
before :each do
|
33
|
+
@l = Language.create :code => 'en-US', :name => 'English'
|
34
|
+
@t = ItemTranslation.create :item => @item, :language => @l, :name => "Book", :desc => "Literature"
|
35
|
+
@t = ItemTranslation.create :item => @item, :language => @l, :name => "Hook", :desc => "Tool"
|
36
|
+
@item.reload
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should return 1 language" do
|
40
|
+
@provider.available_languages.size.should == 1
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should return the right language" do
|
44
|
+
@provider.available_languages.first.should == @l
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "with 3 translations in 2 languages" do
|
50
|
+
|
51
|
+
before :each do
|
52
|
+
@l1 = Language.create :code => 'en-US', :name => 'English'
|
53
|
+
@l2 = Language.create :code => 'de-AT', :name => 'Deutsch'
|
54
|
+
@t = ItemTranslation.create :item => @item, :language => @l1, :name => "Book", :desc => "Literature"
|
55
|
+
@t = ItemTranslation.create :item => @item, :language => @l1, :name => "Hook", :desc => "Tool"
|
56
|
+
@t = ItemTranslation.create :item => @item, :language => @l2, :name => "Haken", :desc => "Werkzeug"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should return 2 language" do
|
60
|
+
@provider.available_languages.size.should == 2
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should return the right language" do
|
64
|
+
@provider.available_languages.first.should == @l1
|
65
|
+
@provider.available_languages.last.should == @l2
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'spec'
|
3
|
+
|
4
|
+
require 'dm-is-remixable'
|
5
|
+
require 'dm-validations'
|
6
|
+
|
7
|
+
require Pathname(__FILE__).dirname.parent.expand_path + 'lib/dm-is-localizable'
|
8
|
+
|
9
|
+
ENV["SQLITE3_SPEC_URI"] ||= 'sqlite3::memory:'
|
10
|
+
ENV["MYSQL_SPEC_URI"] ||= 'mysql://localhost/dm-accepts_nested_attributes_test'
|
11
|
+
ENV["POSTGRES_SPEC_URI"] ||= 'postgres://postgres@localhost/dm-accepts_nested_attributes_test'
|
12
|
+
|
13
|
+
|
14
|
+
def setup_adapter(name, default_uri = nil)
|
15
|
+
begin
|
16
|
+
DataMapper.setup(name, ENV["#{ENV['ADAPTER'].to_s.upcase}_SPEC_URI"] || default_uri)
|
17
|
+
Object.const_set('ADAPTER', ENV['ADAPTER'].to_sym) if name.to_s == ENV['ADAPTER']
|
18
|
+
true
|
19
|
+
rescue Exception => e
|
20
|
+
if name.to_s == ENV['ADAPTER']
|
21
|
+
Object.const_set('ADAPTER', nil)
|
22
|
+
warn "Could not load do_#{name}: #{e}"
|
23
|
+
end
|
24
|
+
false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# have the loggers handy
|
29
|
+
# DataObjects::Logger.new(STDOUT, :debug)
|
30
|
+
# DataObjects::Sqlite3.logger = DataObjects::Logger.new(STDOUT, :debug)
|
31
|
+
|
32
|
+
# -----------------------------------------------
|
33
|
+
# support for nice html output in rspec tmbundle
|
34
|
+
# -----------------------------------------------
|
35
|
+
|
36
|
+
USE_TEXTMATE_RSPEC_BUNDLE = true # set to false if not using textmate
|
37
|
+
|
38
|
+
if USE_TEXTMATE_RSPEC_BUNDLE
|
39
|
+
|
40
|
+
require Pathname(__FILE__).dirname.expand_path + 'lib/rspec_tmbundle_support'
|
41
|
+
|
42
|
+
# use the tmbundle logger
|
43
|
+
RSpecTmBundleHelpers::TextmateRspecLogger.new(STDOUT, :off)
|
44
|
+
|
45
|
+
|
46
|
+
class Object
|
47
|
+
include RSpecTmBundleHelpers
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
ENV['ADAPTER'] ||= 'sqlite3'
|
53
|
+
setup_adapter(:default)
|
54
|
+
Dir[Pathname(__FILE__).dirname.to_s + "/fixtures/**/*.rb"].each { |rb| require(rb) }
|
55
|
+
|
56
|
+
|
57
|
+
Spec::Runner.configure do |config|
|
58
|
+
|
59
|
+
config.before(:all) do
|
60
|
+
DataMapper.auto_migrate!
|
61
|
+
end
|
62
|
+
|
63
|
+
config.before(:each) do
|
64
|
+
DataMapper.repository(:default) do |r|
|
65
|
+
transaction = DataMapper::Transaction.new(r)
|
66
|
+
transaction.begin
|
67
|
+
r.adapter.push_transaction(transaction)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
config.after(:each) do
|
72
|
+
DataMapper.repository(:default) do |r|
|
73
|
+
adapter = r.adapter
|
74
|
+
while adapter.current_transaction
|
75
|
+
adapter.current_transaction.rollback
|
76
|
+
adapter.pop_transaction
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|