globalize2 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/LICENSE +21 -0
- data/README.textile +202 -0
- data/Rakefile +39 -0
- data/VERSION +1 -0
- data/generators/db_backend.rb +0 -0
- data/generators/templates/db_backend_migration.rb +25 -0
- data/globalize2.gemspec +100 -0
- data/init.rb +8 -0
- data/lib/globalize/backend/chain.rb +102 -0
- data/lib/globalize/backend/pluralizing.rb +37 -0
- data/lib/globalize/backend/static.rb +61 -0
- data/lib/globalize/i18n/missing_translations_log_handler.rb +41 -0
- data/lib/globalize/i18n/missing_translations_raise_handler.rb +27 -0
- data/lib/globalize/load_path.rb +63 -0
- data/lib/globalize/locale/fallbacks.rb +63 -0
- data/lib/globalize/locale/language_tag.rb +81 -0
- data/lib/globalize/model/active_record.rb +56 -0
- data/lib/globalize/model/active_record/adapter.rb +100 -0
- data/lib/globalize/model/active_record/translated.rb +174 -0
- data/lib/globalize/translation.rb +32 -0
- data/lib/locale/root.yml +3 -0
- data/lib/rails_edge_load_path_patch.rb +40 -0
- data/notes.textile +51 -0
- data/test/all.rb +2 -0
- data/test/backends/chained_test.rb +175 -0
- data/test/backends/pluralizing_test.rb +63 -0
- data/test/backends/static_test.rb +147 -0
- data/test/data/locale/all.yml +2 -0
- data/test/data/locale/de-DE.yml +2 -0
- data/test/data/locale/en-US.yml +2 -0
- data/test/data/locale/en-US/module.yml +2 -0
- data/test/data/locale/fi-FI/module.yml +2 -0
- data/test/data/locale/root.yml +0 -0
- data/test/data/models.rb +40 -0
- data/test/data/no_globalize_schema.rb +11 -0
- data/test/data/schema.rb +39 -0
- data/test/i18n/missing_translations_test.rb +36 -0
- data/test/load_path_test.rb +49 -0
- data/test/locale/fallbacks_test.rb +154 -0
- data/test/locale/language_tag_test.rb +130 -0
- data/test/model/active_record/migration_test.rb +123 -0
- data/test/model/active_record/sti_translated_test.rb +75 -0
- data/test/model/active_record/translated_test.rb +487 -0
- data/test/test_helper.rb +36 -0
- data/test/translation_test.rb +54 -0
- metadata +116 -0
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
|
3
|
+
module Globalize
|
4
|
+
module Model
|
5
|
+
class MigrationError < StandardError; end
|
6
|
+
class MigrationMissingTranslatedField < MigrationError; end
|
7
|
+
class BadMigrationFieldType < MigrationError; end
|
8
|
+
|
9
|
+
module ActiveRecord
|
10
|
+
module Translated
|
11
|
+
def self.included(base)
|
12
|
+
base.extend ActMethods
|
13
|
+
end
|
14
|
+
|
15
|
+
module ActMethods
|
16
|
+
def translates(*attr_names)
|
17
|
+
options = attr_names.extract_options!
|
18
|
+
options[:translated_attributes] = attr_names
|
19
|
+
|
20
|
+
# Only set up once per class
|
21
|
+
unless included_modules.include? InstanceMethods
|
22
|
+
class_inheritable_accessor :globalize_options, :globalize_proxy
|
23
|
+
|
24
|
+
include InstanceMethods
|
25
|
+
extend ClassMethods
|
26
|
+
|
27
|
+
self.globalize_proxy = Globalize::Model::ActiveRecord.create_proxy_class(self)
|
28
|
+
has_many(
|
29
|
+
:globalize_translations,
|
30
|
+
:class_name => globalize_proxy.name,
|
31
|
+
:extend => Extensions,
|
32
|
+
:dependent => :delete_all,
|
33
|
+
:foreign_key => class_name.foreign_key
|
34
|
+
)
|
35
|
+
|
36
|
+
after_save :update_globalize_record
|
37
|
+
end
|
38
|
+
|
39
|
+
self.globalize_options = options
|
40
|
+
Globalize::Model::ActiveRecord.define_accessors(self, attr_names)
|
41
|
+
|
42
|
+
# Import any callbacks that have been defined by extensions to Globalize2
|
43
|
+
# and run them.
|
44
|
+
extend Callbacks
|
45
|
+
Callbacks.instance_methods.each { |callback| send(callback) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def locale=(locale)
|
49
|
+
@@locale = locale
|
50
|
+
end
|
51
|
+
|
52
|
+
def locale
|
53
|
+
(defined?(@@locale) && @@locale) || I18n.locale
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Dummy Callbacks module. Extensions to Globalize2 can insert methods into here
|
58
|
+
# and they'll be called at the end of the translates class method.
|
59
|
+
module Callbacks
|
60
|
+
end
|
61
|
+
|
62
|
+
# Extension to the has_many :globalize_translations association
|
63
|
+
module Extensions
|
64
|
+
def by_locales(locales)
|
65
|
+
find :all, :conditions => { :locale => locales.map(&:to_s) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module ClassMethods
|
70
|
+
def method_missing(method, *args)
|
71
|
+
if method.to_s =~ /^find_by_(\w+)$/ && globalize_options[:translated_attributes].include?($1.to_sym)
|
72
|
+
find(:first, :joins => :globalize_translations,
|
73
|
+
:conditions => [ "#{i18n_attr($1)} = ? AND #{i18n_attr('locale')} IN (?)",
|
74
|
+
args.first,I18n.fallbacks[I18n.locale].map{|tag| tag.to_s}])
|
75
|
+
else
|
76
|
+
super
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def create_translation_table!(fields)
|
81
|
+
translated_fields = self.globalize_options[:translated_attributes]
|
82
|
+
translated_fields.each do |f|
|
83
|
+
raise MigrationMissingTranslatedField, "Missing translated field #{f}" unless fields[f]
|
84
|
+
end
|
85
|
+
|
86
|
+
fields.each do |name, type|
|
87
|
+
if translated_fields.include?(name) && ![:string, :text].include?(type)
|
88
|
+
raise BadMigrationFieldType, "Bad field type for #{name}, should be :string or :text"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
self.connection.create_table(translation_table_name) do |t|
|
93
|
+
t.references self.table_name.singularize
|
94
|
+
t.string :locale
|
95
|
+
fields.each do |name, type|
|
96
|
+
t.column name, type
|
97
|
+
end
|
98
|
+
t.timestamps
|
99
|
+
end
|
100
|
+
|
101
|
+
self.connection.add_index(translation_table_name, "#{self.table_name.singularize}_id", :name => translation_index_name)
|
102
|
+
end
|
103
|
+
|
104
|
+
def set_translation_table_name(table_name)
|
105
|
+
globalize_proxy.set_table_name(table_name)
|
106
|
+
end
|
107
|
+
|
108
|
+
def translation_table_name
|
109
|
+
globalize_proxy.table_name
|
110
|
+
end
|
111
|
+
|
112
|
+
def translation_index_name
|
113
|
+
# FIXME what's the max size of an index name?
|
114
|
+
index_name = "index_#{translation_table_name}_on_#{self.table_name.singularize}_id"
|
115
|
+
index_name.size < 50 ? index_name : "index_#{Digest::SHA1.hexdigest(index_name)}"
|
116
|
+
end
|
117
|
+
|
118
|
+
def drop_translation_table!
|
119
|
+
self.connection.remove_index(translation_table_name, :name => translation_index_name)
|
120
|
+
self.connection.drop_table translation_table_name
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def i18n_attr(attribute_name)
|
126
|
+
self.base_class.name.underscore.gsub('/', '_') + "_translations.#{attribute_name}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
module InstanceMethods
|
131
|
+
def reload(options = nil)
|
132
|
+
globalize.clear_cache
|
133
|
+
|
134
|
+
# clear all globalized attributes
|
135
|
+
# TODO what's the best way to handle this?
|
136
|
+
self.class.globalize_options[:translated_attributes].each do |attr|
|
137
|
+
@attributes.delete(attr.to_s)
|
138
|
+
end
|
139
|
+
|
140
|
+
super(options)
|
141
|
+
end
|
142
|
+
|
143
|
+
def translated_attributes
|
144
|
+
self.class.globalize_options[:translated_attributes].inject({}) {|h, tf| h[tf] = send(tf); h }
|
145
|
+
end
|
146
|
+
|
147
|
+
def globalize
|
148
|
+
@globalize ||= Adapter.new self
|
149
|
+
end
|
150
|
+
|
151
|
+
def update_globalize_record
|
152
|
+
globalize.update_translations!
|
153
|
+
end
|
154
|
+
|
155
|
+
def translated_locales
|
156
|
+
globalize_translations.scoped(:select => 'DISTINCT locale').map do |translation|
|
157
|
+
translation.locale.to_sym
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def set_translations(options)
|
162
|
+
options.keys.each do |key|
|
163
|
+
translation = globalize_translations.find_by_locale(key.to_s) ||
|
164
|
+
globalize_translations.build(:locale => key.to_s)
|
165
|
+
translation.update_attributes!(options[key])
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
ActiveRecord::Base.send(:include, Globalize::Model::ActiveRecord::Translated)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Globalize
|
2
|
+
# Translations are simple value objects that carry some context information
|
3
|
+
# alongside the actual translation string.
|
4
|
+
|
5
|
+
class Translation < String
|
6
|
+
class Attribute < Translation
|
7
|
+
attr_accessor :requested_locale, :locale, :key
|
8
|
+
end
|
9
|
+
|
10
|
+
class Static < Translation
|
11
|
+
attr_accessor :requested_locale, :locale, :key, :options, :plural_key, :original
|
12
|
+
|
13
|
+
def initialize(string, meta = nil)
|
14
|
+
self.original = string
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(string, meta = nil)
|
20
|
+
set_meta meta
|
21
|
+
super string
|
22
|
+
end
|
23
|
+
|
24
|
+
def fallback?
|
25
|
+
locale.to_sym != requested_locale.to_sym
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_meta(meta)
|
29
|
+
meta.each {|name, value| send :"#{name}=", value } if meta
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/locale/root.yml
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module I18n
|
2
|
+
@@load_path = nil
|
3
|
+
@@default_locale = :'en-US'
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def load_path
|
7
|
+
@@load_path ||= []
|
8
|
+
end
|
9
|
+
|
10
|
+
def load_path=(load_path)
|
11
|
+
@@load_path = load_path
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
I18n::Backend::Simple.module_eval do
|
17
|
+
def initialized?
|
18
|
+
@initialized ||= false
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def init_translations
|
24
|
+
load_translations(*I18n.load_path)
|
25
|
+
@initialized = true
|
26
|
+
end
|
27
|
+
|
28
|
+
def lookup(locale, key, scope = [])
|
29
|
+
return unless key
|
30
|
+
init_translations unless initialized?
|
31
|
+
keys = I18n.send :normalize_translation_keys, locale, key, scope
|
32
|
+
keys.inject(translations){|result, k| result[k.to_sym] or return nil }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
rails_dir = File.expand_path "#{File.dirname(__FILE__)}/../../../rails/"
|
37
|
+
paths = %w(actionpack/lib/action_view/locale/en-US.yml
|
38
|
+
activerecord/lib/active_record/locale/en-US.yml
|
39
|
+
activesupport/lib/active_support/locale/en-US.yml)
|
40
|
+
paths.each{|path| I18n.load_path << "#{rails_dir}/#{path}" }
|
data/notes.textile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
Stopped DB Backend in the middle, here's where we left off:
|
2
|
+
|
3
|
+
h1. Some Notes
|
4
|
+
|
5
|
+
* Started doing the migration generator in generators/db_backend.rb
|
6
|
+
* Translation keys will be in dotted string format
|
7
|
+
* Question: Do we need a plural_key column, or can we build it in to the dotted key?
|
8
|
+
* We will probably have to code the following methods from scratch, to optimize db calls:
|
9
|
+
** translate
|
10
|
+
** localize
|
11
|
+
** pluralize
|
12
|
+
* We should refactor @interpolation@ code so that it can be included into backend code without inheriting SimpleBackend
|
13
|
+
** Rationale: interpolation is something done entirely after a string is fetched from the data store
|
14
|
+
** Alternately, it could be done from within the I18n module
|
15
|
+
|
16
|
+
h1. Schema
|
17
|
+
|
18
|
+
There will be two db tables.
|
19
|
+
|
20
|
+
# globalize_translations will have: locale, key, translation, created_at, updated_at.
|
21
|
+
# globalize_translations_map will have: key, translation_id.
|
22
|
+
|
23
|
+
globalize_translations_map will let us easily fetch entire sub-trees of namespaces.
|
24
|
+
However, this table may not be necessary, as it may be feasible to just use key LIKE "some.namespace.%".
|
25
|
+
|
26
|
+
h1. Caching
|
27
|
+
|
28
|
+
We'll almost certainly want to implement caching in the backend. Should probably be a customized
|
29
|
+
implementation based on the Rails caching mechanism, to support memcached, etc.
|
30
|
+
|
31
|
+
h1. Queries
|
32
|
+
|
33
|
+
We'll want to pull in lots of stuff at once and return a single translation based on some
|
34
|
+
quick Ruby selection. The query will look something like this:
|
35
|
+
|
36
|
+
<pre>
|
37
|
+
<code>
|
38
|
+
SELECT * FROM globalize_translations
|
39
|
+
WHERE locale in (<fallbacks>) AND
|
40
|
+
key IN (key, default_key)
|
41
|
+
</code>
|
42
|
+
</pre>
|
43
|
+
|
44
|
+
The Ruby code would then pick the first translation that satisfies a fallback, in fallback order.
|
45
|
+
Of course, the records with the supplied key would take precedence of those with the default key.
|
46
|
+
|
47
|
+
h1. Misc
|
48
|
+
|
49
|
+
We should revisit the :zero plural code. On the one hand it's certainly useful for
|
50
|
+
many apps in many languages. On the other hand it's not mentioned in CLDR, and not a real
|
51
|
+
concept in language pluralization. Right now, I'm feeling it's still a good idea to keep it in.
|
data/test/all.rb
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), '..', 'test_helper' )
|
2
|
+
require 'globalize/backend/chain'
|
3
|
+
|
4
|
+
module Globalize
|
5
|
+
module Backend
|
6
|
+
class Dummy
|
7
|
+
def translate(locale, key, options = {})
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ChainedTest < ActiveSupport::TestCase
|
14
|
+
|
15
|
+
test "instantiates a chained backend and sets test as backend" do
|
16
|
+
assert_nothing_raised { I18n.chain_backends }
|
17
|
+
assert_instance_of Globalize::Backend::Chain, I18n.backend
|
18
|
+
end
|
19
|
+
|
20
|
+
test "passes all given arguments to the chained backends #initialize method" do
|
21
|
+
Globalize::Backend::Chain.expects(:new).with(:spec, :simple)
|
22
|
+
I18n.chain_backends :spec, :simple
|
23
|
+
end
|
24
|
+
|
25
|
+
test "passes all given arguments to #add assuming that they are backends" do
|
26
|
+
# no idea how to spec that
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class AddChainedTest < ActiveSupport::TestCase
|
31
|
+
def setup
|
32
|
+
I18n.backend = Globalize::Backend::Chain.new
|
33
|
+
end
|
34
|
+
|
35
|
+
test "accepts an instance of a backend" do
|
36
|
+
assert_nothing_raised { I18n.backend.add Globalize::Backend::Dummy.new }
|
37
|
+
assert_instance_of Globalize::Backend::Dummy, I18n.backend.send(:backends).first
|
38
|
+
end
|
39
|
+
|
40
|
+
test "accepts a class and instantiates the backend" do
|
41
|
+
assert_nothing_raised { I18n.backend.add Globalize::Backend::Dummy }
|
42
|
+
assert_instance_of Globalize::Backend::Dummy, I18n.backend.send(:backends).first
|
43
|
+
end
|
44
|
+
|
45
|
+
test "accepts a symbol, constantizes test as a backend class and instantiates the backend" do
|
46
|
+
assert_nothing_raised { I18n.backend.add :dummy }
|
47
|
+
assert_instance_of Globalize::Backend::Dummy, I18n.backend.send(:backends).first
|
48
|
+
end
|
49
|
+
|
50
|
+
test "accepts any number of backend instances, classes or symbols" do
|
51
|
+
assert_nothing_raised { I18n.backend.add Globalize::Backend::Dummy.new, Globalize::Backend::Dummy, :dummy }
|
52
|
+
assert_instance_of Globalize::Backend::Dummy, I18n.backend.send(:backends).first
|
53
|
+
assert_equal [ Globalize::Backend::Dummy, Globalize::Backend::Dummy, Globalize::Backend::Dummy ],
|
54
|
+
I18n.backend.send(:backends).map{|backend| backend.class }
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
class TranslateChainedTest < ActiveSupport::TestCase
|
60
|
+
def setup
|
61
|
+
I18n.locale = :en
|
62
|
+
I18n.backend = Globalize::Backend::Chain.new
|
63
|
+
@first_backend = I18n::Backend::Simple.new
|
64
|
+
@last_backend = I18n::Backend::Simple.new
|
65
|
+
I18n.backend.add @first_backend
|
66
|
+
I18n.backend.add @last_backend
|
67
|
+
end
|
68
|
+
|
69
|
+
test "delegates #translate to all backends in the order they were added" do
|
70
|
+
@first_backend.expects(:translate).with(:en, :foo, {})
|
71
|
+
@last_backend.expects(:translate).with(:en, :foo, {})
|
72
|
+
I18n.translate :foo
|
73
|
+
end
|
74
|
+
|
75
|
+
test "returns the result from #translate from the first backend if test's not nil" do
|
76
|
+
@first_backend.store_translations :en, {:foo => 'foo from first backend'}
|
77
|
+
@last_backend.store_translations :en, {:foo => 'foo from last backend'}
|
78
|
+
result = I18n.translate :foo
|
79
|
+
assert_equal 'foo from first backend', result
|
80
|
+
end
|
81
|
+
|
82
|
+
test "returns the result from #translate from the second backend if the first one returned nil" do
|
83
|
+
@first_backend.store_translations :en, {}
|
84
|
+
@last_backend.store_translations :en, {:foo => 'foo from last backend'}
|
85
|
+
result = I18n.translate :foo
|
86
|
+
assert_equal 'foo from last backend', result
|
87
|
+
end
|
88
|
+
|
89
|
+
test "looks up a namespace from all backends and merges them (if a result is a hash and no count option is present)" do
|
90
|
+
@first_backend.store_translations :en, {:foo => {:bar => 'bar from first backend'}}
|
91
|
+
@last_backend.store_translations :en, {:foo => {:baz => 'baz from last backend'}}
|
92
|
+
result = I18n.translate :foo
|
93
|
+
assert_equal( {:bar => 'bar from first backend', :baz => 'baz from last backend'}, result )
|
94
|
+
end
|
95
|
+
|
96
|
+
test "raises a MissingTranslationData exception if no translation was found" do
|
97
|
+
assert_raise( I18n::MissingTranslationData ) { I18n.translate :not_here, :raise => true }
|
98
|
+
end
|
99
|
+
|
100
|
+
test "raises an InvalidLocale exception if the locale is nil" do
|
101
|
+
assert_raise( I18n::InvalidLocale ) { Globalize::Backend::Chain.new.translate nil, :foo }
|
102
|
+
end
|
103
|
+
|
104
|
+
test "bulk translates a number of keys from different backends" do
|
105
|
+
@first_backend.store_translations :en, {:foo => 'foo from first backend'}
|
106
|
+
@last_backend.store_translations :en, {:bar => 'bar from last backend'}
|
107
|
+
result = I18n.translate [:foo, :bar]
|
108
|
+
assert_equal( ['foo from first backend', 'bar from last backend'], result )
|
109
|
+
end
|
110
|
+
|
111
|
+
test "still calls #translate on all the backends" do
|
112
|
+
@last_backend.expects :translate
|
113
|
+
I18n.translate :not_here, :default => 'default'
|
114
|
+
end
|
115
|
+
|
116
|
+
test "returns a given default string when no backend returns a translation" do
|
117
|
+
result = I18n.translate :not_here, :default => 'default'
|
118
|
+
assert_equal 'default', result
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
class CustomLocalizeBackend < I18n::Backend::Simple
|
124
|
+
def localize(locale, object, format = :default)
|
125
|
+
"result from custom localize backend" if locale == 'custom'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class LocalizeChainedTest < ActiveSupport::TestCase
|
130
|
+
def setup
|
131
|
+
I18n.locale = :en
|
132
|
+
I18n.backend = Globalize::Backend::Chain.new
|
133
|
+
@first_backend = CustomLocalizeBackend.new
|
134
|
+
@last_backend = I18n::Backend::Simple.new
|
135
|
+
I18n.backend.add @first_backend
|
136
|
+
I18n.backend.add @last_backend
|
137
|
+
@time = Time.now
|
138
|
+
end
|
139
|
+
|
140
|
+
test "delegates #localize to all backends in the order they were added" do
|
141
|
+
@first_backend.expects(:localize).with(:en, @time, :default)
|
142
|
+
@last_backend.expects(:localize).with(:en, @time, :default)
|
143
|
+
I18n.localize @time
|
144
|
+
end
|
145
|
+
|
146
|
+
test "returns the result from #localize from the first backend if test's not nil" do
|
147
|
+
@last_backend.expects(:localize).never
|
148
|
+
result = I18n.localize @time, :locale => 'custom'
|
149
|
+
assert_equal 'result from custom localize backend', result
|
150
|
+
end
|
151
|
+
|
152
|
+
test "returns the result from #localize from the second backend if the first one returned nil" do
|
153
|
+
@last_backend.expects(:localize).returns "value from last backend"
|
154
|
+
result = I18n.localize @time
|
155
|
+
assert_equal 'value from last backend', result
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
class NamespaceChainedTest < ActiveSupport::TestCase
|
160
|
+
def setup
|
161
|
+
@backend = Globalize::Backend::Chain.new
|
162
|
+
end
|
163
|
+
|
164
|
+
test "returns false if the given result is not a Hash" do
|
165
|
+
assert !@backend.send(:namespace_lookup?, 'foo', {})
|
166
|
+
end
|
167
|
+
|
168
|
+
test "returns false if a count option is present" do
|
169
|
+
assert !@backend.send(:namespace_lookup?, {:foo => 'foo'}, {:count => 1})
|
170
|
+
end
|
171
|
+
|
172
|
+
test "returns true if the given result is a Hash AND no count option is present" do
|
173
|
+
assert @backend.send(:namespace_lookup?, {:foo => 'foo'}, {})
|
174
|
+
end
|
175
|
+
end
|