splash 0.0.1.alpha
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/Rakefile +19 -0
- data/lib/splash/acts_as_collection.rb +55 -0
- data/lib/splash/acts_as_scope.rb +118 -0
- data/lib/splash/acts_as_scope_root.rb +10 -0
- data/lib/splash/annotated.rb +34 -0
- data/lib/splash/application.rb +36 -0
- data/lib/splash/attribute.rb +45 -0
- data/lib/splash/attributed_struct.rb +8 -0
- data/lib/splash/collection.rb +52 -0
- data/lib/splash/connection.rb +26 -0
- data/lib/splash/constraint/all.rb +24 -0
- data/lib/splash/constraint/any.rb +13 -0
- data/lib/splash/constraint/in.rb +13 -0
- data/lib/splash/constraint/not_nil.rb +9 -0
- data/lib/splash/constraint.rb +62 -0
- data/lib/splash/document.rb +38 -0
- data/lib/splash/embed.rb +37 -0
- data/lib/splash/has_attributes.rb +146 -0
- data/lib/splash/has_constraint.rb +9 -0
- data/lib/splash/namespace.rb +67 -0
- data/lib/splash/password.rb +31 -0
- data/lib/splash/persister.rb +66 -0
- data/lib/splash/query_interface.rb +84 -0
- data/lib/splash/saveable.rb +141 -0
- data/lib/splash/scope/options.rb +58 -0
- data/lib/splash/scope.rb +46 -0
- data/lib/splash/scope_delegator.rb +14 -0
- data/lib/splash/scope_options.rb +31 -0
- data/lib/splash/standart_extensions/hash.rb +45 -0
- data/lib/splash/standart_extensions/module.rb +73 -0
- data/lib/splash/standart_extensions/object.rb +11 -0
- data/lib/splash/standart_extensions/string.rb +5 -0
- data/lib/splash/validates.rb +75 -0
- data/lib/splash/validator.rb +24 -0
- data/lib/splash.rb +35 -0
- data/spec/helper.rb +15 -0
- data/spec/lib/annotated_spec.rb +87 -0
- data/spec/lib/collection_spec.rb +64 -0
- data/spec/lib/has_attributes_spec.rb +43 -0
- data/spec/lib/has_constraints_spec.rb +53 -0
- data/spec/lib/inheritance_spec.rb +69 -0
- metadata +139 -0
@@ -0,0 +1,146 @@
|
|
1
|
+
module Splash
|
2
|
+
module HasAttributes
|
3
|
+
|
4
|
+
class Attributes < Hash
|
5
|
+
def load(raw)
|
6
|
+
raw.each do |key,value|
|
7
|
+
key=key.to_s
|
8
|
+
|
9
|
+
|
10
|
+
if value.kind_of? type(key).persisted_class
|
11
|
+
self[key]=value
|
12
|
+
elsif Splash::Persister.raw? value
|
13
|
+
@raw[key]=value
|
14
|
+
else
|
15
|
+
|
16
|
+
puts value.class
|
17
|
+
puts type(key).persisted_class
|
18
|
+
raise "Don't know what to do with #{key}= #{value.inspect}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def load_raw(raw)
|
24
|
+
@raw.update(raw)
|
25
|
+
end
|
26
|
+
|
27
|
+
def [](key)
|
28
|
+
return super if( self.key? key )
|
29
|
+
t=type(key)
|
30
|
+
if( @raw.key? key )
|
31
|
+
value = t.read(@raw[key])
|
32
|
+
else
|
33
|
+
value = t.default
|
34
|
+
end
|
35
|
+
return self[key]=value
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(klass)
|
39
|
+
super()
|
40
|
+
@class = klass
|
41
|
+
@raw = {}
|
42
|
+
end
|
43
|
+
|
44
|
+
def raw
|
45
|
+
write_back!
|
46
|
+
return @raw
|
47
|
+
end
|
48
|
+
|
49
|
+
def type(key)
|
50
|
+
return @class.attribute(key)
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
def write_back!
|
55
|
+
self.each do |key,value|
|
56
|
+
@raw[key]=type(key).write(value)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class << self
|
62
|
+
def included(base)
|
63
|
+
base.extend(ClassMethods)
|
64
|
+
base.instance_eval do
|
65
|
+
merged_inheritable_attr :attributes,{}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_persister(*args,&block)
|
70
|
+
klass = Object
|
71
|
+
if args.length > 0
|
72
|
+
if args.first.respond_to? :persister
|
73
|
+
klass = args.shift
|
74
|
+
end
|
75
|
+
end
|
76
|
+
type = (klass).persister
|
77
|
+
result=type.new(*args,&block)
|
78
|
+
result.persist_class(klass)
|
79
|
+
return result
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def attributes
|
84
|
+
@attributes ||= Attributes.new(self.class)
|
85
|
+
end
|
86
|
+
|
87
|
+
def attribute(name)
|
88
|
+
self.class.attribute(name)
|
89
|
+
end
|
90
|
+
|
91
|
+
def respond_to?(meth)
|
92
|
+
return true if meth =~/^([a-zA-Z_]+)\?$/
|
93
|
+
return true if meth =~ /^([a-zA-Z_]+)=$/
|
94
|
+
super(meth)
|
95
|
+
end
|
96
|
+
|
97
|
+
def inspect
|
98
|
+
"#{self.class.to_s}{#{attributes.inspect}}"
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_saveable
|
102
|
+
attributes.raw
|
103
|
+
end
|
104
|
+
|
105
|
+
def method_missing(meth,*args,&block)
|
106
|
+
if( meth.to_s =~ /^([a-zA-Z_]+)=$/ && args.size == 1 )
|
107
|
+
# setter
|
108
|
+
return attributes[$1]=args.first
|
109
|
+
elsif( meth.to_s =~ /^([a-zA-Z_]+)$/ && args.size == 0 )
|
110
|
+
return attributes[$1]
|
111
|
+
elsif( meth.to_s =~ /^([a-zA-Z_]+)\?$/ && args.size == 0 )
|
112
|
+
return attributes.key?(meth.to_s)
|
113
|
+
end
|
114
|
+
super
|
115
|
+
end
|
116
|
+
|
117
|
+
module ClassMethods
|
118
|
+
|
119
|
+
def attribute_accessor(name)
|
120
|
+
self.class_eval <<-CODE, __FILE__, __LINE__
|
121
|
+
def #{name.to_s}() return attributes[#{name.to_s.inspect}] end
|
122
|
+
def #{name.to_s}=(value) return attributes[#{name.to_s.inspect}] = value end
|
123
|
+
CODE
|
124
|
+
end
|
125
|
+
|
126
|
+
def def_attribute(name,*args,&block)
|
127
|
+
name = name.to_s
|
128
|
+
attr=attributes[name]=Splash::Attribute.new(*args, &block)
|
129
|
+
attribute_accessor(name)
|
130
|
+
return attr
|
131
|
+
end
|
132
|
+
|
133
|
+
def attribute(name,create = true)
|
134
|
+
name = name.to_s
|
135
|
+
each_attributes do |attr|
|
136
|
+
return attr[name] if attr.key? name
|
137
|
+
end
|
138
|
+
if create
|
139
|
+
return def_attribute(name)
|
140
|
+
end
|
141
|
+
return nil
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "logger"
|
2
|
+
module Splash
|
3
|
+
class NameSpace
|
4
|
+
|
5
|
+
URI_MATCHER = /^mongodb:\/\/([^\/:@]+)(:\d+|)\/(.*)/
|
6
|
+
|
7
|
+
LOGGER = ::Logger.new(STDOUT)
|
8
|
+
#LOGGER.level = Logger::WARN
|
9
|
+
|
10
|
+
attr_reader :db
|
11
|
+
|
12
|
+
def self.default
|
13
|
+
@default ||= self.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.default=(value)
|
17
|
+
@default = value
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(uri='mongodb://localhost/splash')
|
21
|
+
match = URI_MATCHER.match(uri)
|
22
|
+
if match.nil?
|
23
|
+
@db = Mongo::Connection.from_uri(uri,:logger=>LOGGER)
|
24
|
+
else
|
25
|
+
@db = Mongo::Connection.new(match[1],match[2].length==0 ? nil : match[2].to_i,:logger=>LOGGER).db(match[3])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def clear!
|
30
|
+
@db.collections.each do |collection|
|
31
|
+
begin
|
32
|
+
collection.drop
|
33
|
+
rescue Mongo::OperationFailure
|
34
|
+
end
|
35
|
+
end
|
36
|
+
return true
|
37
|
+
end
|
38
|
+
|
39
|
+
def collection_for(klass)
|
40
|
+
@class_collection_map ||= {}
|
41
|
+
@top_classes ||={}
|
42
|
+
return @class_collection_map[klass] if( @class_collection_map.key? klass)
|
43
|
+
|
44
|
+
|
45
|
+
classes=Saveable.get_class_hierachie(klass)
|
46
|
+
|
47
|
+
collection=@db.collection(classes.last.to_s.gsub(/(<?[a-z])([A-Z])/){ |c| c[0,1]+"_"+c[1,2].downcase }.gsub("::",".").downcase)
|
48
|
+
|
49
|
+
@top_classes[collection.name] = classes.last
|
50
|
+
|
51
|
+
classes.each do |klass|
|
52
|
+
@class_collection_map[klass]=collection
|
53
|
+
end
|
54
|
+
|
55
|
+
return collection
|
56
|
+
end
|
57
|
+
|
58
|
+
def class_for(collection_name)
|
59
|
+
@top_classes[collection_name]
|
60
|
+
end
|
61
|
+
|
62
|
+
def dereference(dbref)
|
63
|
+
self.class_for(dbref.namespace)[dbref.object_id]
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
class Splash::Password
|
5
|
+
|
6
|
+
include Splash::Embed
|
7
|
+
|
8
|
+
DIGESTER = Digest::SHA1
|
9
|
+
|
10
|
+
def_attribute( 'salt' )
|
11
|
+
|
12
|
+
def_attribute( 'hash' )
|
13
|
+
|
14
|
+
def matches?(string)
|
15
|
+
DIGESTER.hexdigest("#{string}#{self.salt}") == self.hash
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(str_or_args={})
|
19
|
+
if str_or_args.kind_of? String
|
20
|
+
slt = SecureRandom.hex
|
21
|
+
hash = DIGESTER.hexdigest("#{str_or_args}#{slt}")
|
22
|
+
super({'salt'=>slt,'hash'=>hash})
|
23
|
+
elsif str_or_args.kind_of? Hash
|
24
|
+
super(str_or_args)
|
25
|
+
else
|
26
|
+
super({})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
class Splash::Persister
|
2
|
+
|
3
|
+
RAW_TYPES=[String,NilClass,Numeric,FalseClass,TrueClass,BSON::ObjectID,Time]
|
4
|
+
|
5
|
+
attr_reader :persisted_class
|
6
|
+
|
7
|
+
def read(value)
|
8
|
+
return value
|
9
|
+
end
|
10
|
+
|
11
|
+
def write(value)
|
12
|
+
return value
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.raw?(value)
|
16
|
+
return true if RAW_TYPES.any? do |type| value.class == type end
|
17
|
+
if value.kind_of?(Hash) || value.kind_of?(Array)
|
18
|
+
value.each do |key,val|
|
19
|
+
return false unless self.raw?(key)
|
20
|
+
return false unless self.raw?(val)
|
21
|
+
end
|
22
|
+
return true
|
23
|
+
elsif value.kind_of?(Array)
|
24
|
+
value.each do |sub|
|
25
|
+
return false unless self.raw?(sub)
|
26
|
+
end
|
27
|
+
return true
|
28
|
+
end
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(config={},&block)
|
33
|
+
self.config= default_config.merge(config)
|
34
|
+
if block_given?
|
35
|
+
instance_eval &block
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def persist_class(klass)
|
40
|
+
@persisted_class=klass
|
41
|
+
end
|
42
|
+
|
43
|
+
def persisted_class()
|
44
|
+
@persisted_class
|
45
|
+
end
|
46
|
+
|
47
|
+
def bind_to(klass)
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def default(object)
|
52
|
+
@config[:default]
|
53
|
+
end
|
54
|
+
|
55
|
+
def missing(object)
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
def default_config
|
61
|
+
{:default=>nil,:read=>nil,:write=>nil}
|
62
|
+
end
|
63
|
+
def config=(conf)
|
64
|
+
@config=conf
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Splash
|
2
|
+
module QueryInterface
|
3
|
+
|
4
|
+
%w(preload nopreload limit conditions fieldmode with_id extend_scoped sort).each do |fct|
|
5
|
+
class_eval <<-CODE, __FILE__,__LINE__
|
6
|
+
def #{fct}(*args,&block)
|
7
|
+
query(query_#{fct}(*args,&block))
|
8
|
+
end
|
9
|
+
def #{fct}!(*args,&block)
|
10
|
+
query!(query_#{fct}(*args,&block))
|
11
|
+
end
|
12
|
+
protected :#{fct}!
|
13
|
+
CODE
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def query_preload(*field)
|
19
|
+
fields=field.flatten.inject({}){|hsh,key|
|
20
|
+
hsh[key.to_s]=1
|
21
|
+
hsh
|
22
|
+
}
|
23
|
+
return {:fields=>fields}
|
24
|
+
end
|
25
|
+
|
26
|
+
def query_nopreload(*field)
|
27
|
+
fields=field.flatten.inject({}){|hsh,key|
|
28
|
+
hsh[key.to_s]=0
|
29
|
+
hsh
|
30
|
+
}
|
31
|
+
return {:fields=>fields}
|
32
|
+
end
|
33
|
+
|
34
|
+
def query_limit(limit)
|
35
|
+
return {:limit=>limit}
|
36
|
+
end
|
37
|
+
|
38
|
+
def query_conditions(conditions)
|
39
|
+
return {:selector=>conditions}
|
40
|
+
end
|
41
|
+
|
42
|
+
def query_default_attributes(values)
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def query_with_id(*args)
|
47
|
+
ids=args.flatten.map &:to_bson
|
48
|
+
if ids.size == 1
|
49
|
+
return {:selector=>{"_id"=>ids.first}}
|
50
|
+
else
|
51
|
+
return {:selector=>{"_id"=>{"$in"=>ids}}}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
def query_fieldmode(type)
|
55
|
+
return {:fieldmode=>type}
|
56
|
+
end
|
57
|
+
|
58
|
+
def query_sort(*args)
|
59
|
+
result=[]
|
60
|
+
args.each do |arg|
|
61
|
+
if arg.kind_of? String
|
62
|
+
result << [arg,'ascending']
|
63
|
+
elsif arg.kind_of? Hash
|
64
|
+
result += arg.to_a
|
65
|
+
end
|
66
|
+
end
|
67
|
+
return {:sort=>result}
|
68
|
+
end
|
69
|
+
|
70
|
+
def query_extend_scoped(*modules,&block)
|
71
|
+
if block_given?
|
72
|
+
m=Module.new
|
73
|
+
m.class_eval &block
|
74
|
+
modules << m
|
75
|
+
end
|
76
|
+
|
77
|
+
modules.each do |mod|
|
78
|
+
self.extend(mod)
|
79
|
+
end
|
80
|
+
|
81
|
+
return {:extend_scoped => modules}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module Splash
|
2
|
+
module Saveable
|
3
|
+
class Persister < Splash::Persister
|
4
|
+
def write(value)
|
5
|
+
return nil if value.nil?
|
6
|
+
return value._id
|
7
|
+
end
|
8
|
+
|
9
|
+
def read(value)
|
10
|
+
return nil if value.nil?
|
11
|
+
return persisted_class.with_id(value).first
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class MultiPersister < Splash::Persister
|
16
|
+
def write(value)
|
17
|
+
return nil if value.nil?
|
18
|
+
return BSON::DBRef.new(value.class.collection.name,value._id)
|
19
|
+
end
|
20
|
+
|
21
|
+
def read(value)
|
22
|
+
return nil if value.nil?
|
23
|
+
return @persisted_class.namespace.dereference(value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class EmbedPersister < Splash::Persister
|
28
|
+
def write(value)
|
29
|
+
return nil if value.nil?
|
30
|
+
return Saveable.wrap(value)
|
31
|
+
end
|
32
|
+
|
33
|
+
def read(value)
|
34
|
+
return nil if value.nil?
|
35
|
+
return Saveable.load(value,persisted_class)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
self.persister= MultiPersister
|
40
|
+
|
41
|
+
|
42
|
+
UPPERCASE=65..90
|
43
|
+
|
44
|
+
class << self
|
45
|
+
def included(base)
|
46
|
+
base.extend(ClassMethods)
|
47
|
+
base.persister=Splash::Saveable::Persister
|
48
|
+
end
|
49
|
+
|
50
|
+
def unwrap(keys)
|
51
|
+
keys.inject({}) do |hsh,(key,val)| hsh[key]=val unless UPPERCASE.include? key[0]; hsh end
|
52
|
+
end
|
53
|
+
|
54
|
+
def wrap(object)
|
55
|
+
object.to_saveable.merge("Type"=>Saveable.get_class_hierachie(object.class).map(&:to_s))
|
56
|
+
end
|
57
|
+
|
58
|
+
def load(keys,klass=Hash)
|
59
|
+
if keys.nil?
|
60
|
+
keys={}
|
61
|
+
end
|
62
|
+
if keys["Type"]
|
63
|
+
klass = Kernel.eval(keys["Type"].first)
|
64
|
+
end
|
65
|
+
k = klass.new()
|
66
|
+
k.attributes.load_raw(self.unwrap(keys))
|
67
|
+
return k
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_saveable(obj)
|
71
|
+
if obj.respond_to? :to_saveable
|
72
|
+
return obj.to_saveable
|
73
|
+
end
|
74
|
+
return obj
|
75
|
+
end
|
76
|
+
|
77
|
+
def get_class_hierachie(klass)
|
78
|
+
base=[]
|
79
|
+
begin
|
80
|
+
if klass.named?
|
81
|
+
base << klass
|
82
|
+
end
|
83
|
+
#return base unless klass.instance_of? Class
|
84
|
+
klass = klass.superclass
|
85
|
+
end while ( klass < Splash::HasAttributes )
|
86
|
+
return base
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def namespace
|
91
|
+
self.class.namespace
|
92
|
+
end
|
93
|
+
|
94
|
+
def storable_id
|
95
|
+
self.attributes["_id"]
|
96
|
+
end
|
97
|
+
|
98
|
+
def store!
|
99
|
+
self.attributes["_id"]=self.class.store!(self)
|
100
|
+
return self
|
101
|
+
end
|
102
|
+
|
103
|
+
def remove!
|
104
|
+
return self.class.collection.remove('_id'=>self._id)
|
105
|
+
end
|
106
|
+
|
107
|
+
def stored?
|
108
|
+
return !storable_id.nil?
|
109
|
+
end
|
110
|
+
|
111
|
+
def find_self
|
112
|
+
self.class.with_id(self.storable_id)
|
113
|
+
end
|
114
|
+
|
115
|
+
module ClassMethods
|
116
|
+
|
117
|
+
def store!(object)
|
118
|
+
return self.collection.save(
|
119
|
+
Saveable.wrap(object)
|
120
|
+
);
|
121
|
+
end
|
122
|
+
|
123
|
+
def namespace
|
124
|
+
@namespace ||= Splash::NameSpace.default
|
125
|
+
end
|
126
|
+
|
127
|
+
def collection
|
128
|
+
@collection ||= namespace.collection_for(self)
|
129
|
+
end
|
130
|
+
|
131
|
+
def [](*args)
|
132
|
+
a=args.flatten
|
133
|
+
if a.length == 1
|
134
|
+
return with_id(a).first
|
135
|
+
else
|
136
|
+
return with_id(a).finish!
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class Splash::Scope::Options
|
2
|
+
|
3
|
+
OPTION_KEYS=[:fields,:limit,:sort]
|
4
|
+
def self.cast(hsh)
|
5
|
+
if hsh.kind_of? self
|
6
|
+
return hsh
|
7
|
+
end
|
8
|
+
return self.new(hsh)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(hsh=nil)
|
12
|
+
@options={:selector=>{},:fieldmode=>:exclude,:extend_scoped=>[],:limit=>0,:sort=>[]}
|
13
|
+
@options.merge! hsh if hsh
|
14
|
+
@options.freeze
|
15
|
+
end
|
16
|
+
|
17
|
+
def merge(options)
|
18
|
+
self.class.new(Splash::Scope::Options.merge_options(@options,options))
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.merge_options(a,b)
|
22
|
+
return {
|
23
|
+
:selector => a[:selector].deep_merge(b[:selector]),
|
24
|
+
:fieldmode => (b[:fieldmode] || a[:fieldmode]),
|
25
|
+
:extend_scoped => (a[:extend_scoped] + (b[:extend_scoped] || [])),
|
26
|
+
:limit => (b[:limit] || a[:limit]),
|
27
|
+
:sort => (a[:sort] + (b[:sort] || []))
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def extensions
|
32
|
+
@options[:extend_scoped] || []
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_h
|
36
|
+
@options
|
37
|
+
end
|
38
|
+
|
39
|
+
def selector
|
40
|
+
@options[:selector]
|
41
|
+
end
|
42
|
+
|
43
|
+
def options
|
44
|
+
opt=@options.reject{|key,value| !(OPTION_KEYS.include? key)}
|
45
|
+
if opt.key? :fields
|
46
|
+
if @options[:fieldmode]==:eager
|
47
|
+
opt.delete :fields
|
48
|
+
else
|
49
|
+
fieldmode = (@options[:fieldmode]==:include ? 0 : 1)
|
50
|
+
opt[:fields]=opt[:fields].reject{|key,value|
|
51
|
+
value == fieldmode
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
return opt
|
57
|
+
end
|
58
|
+
end
|
data/lib/splash/scope.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require "delegate"
|
2
|
+
module Splash
|
3
|
+
class Scope
|
4
|
+
|
5
|
+
autoload :Options,Splash::DIR+"/splash/scope/options"
|
6
|
+
|
7
|
+
include Splash::ActsAsScope
|
8
|
+
|
9
|
+
def initialize(parent,options)
|
10
|
+
@parent_scope=parent.scope_root
|
11
|
+
@scope_options=options
|
12
|
+
end
|
13
|
+
|
14
|
+
def scope_root?
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def scope_root
|
19
|
+
@parent_scope
|
20
|
+
end
|
21
|
+
|
22
|
+
def respond_to?(meth)
|
23
|
+
load_scope_extensions!
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def load_scope_extensions!
|
29
|
+
unless @scope_extesions_loaded
|
30
|
+
@scope_options.extensions.each do |mod|
|
31
|
+
self.extend(mod)
|
32
|
+
end
|
33
|
+
@scope_extesions_loaded = true
|
34
|
+
return true
|
35
|
+
end
|
36
|
+
return false
|
37
|
+
end
|
38
|
+
def method_missing(meth,*args,&block)
|
39
|
+
if load_scope_extensions!
|
40
|
+
return self.send(meth,*args,&block)
|
41
|
+
end
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class ScopeOptions
|
2
|
+
|
3
|
+
def self.cast(hsh)
|
4
|
+
if hsh.kind_of? self
|
5
|
+
return hsh
|
6
|
+
end
|
7
|
+
return self.new(hsh)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(hsh=nil)
|
11
|
+
@options={:selector=>{},:limit=>-1}
|
12
|
+
@options.merge! hsh if hsh
|
13
|
+
|
14
|
+
@options.freeze
|
15
|
+
end
|
16
|
+
|
17
|
+
def merge(options)
|
18
|
+
self.class.new(@options.merge(options.to_h))
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_h
|
22
|
+
@options
|
23
|
+
end
|
24
|
+
|
25
|
+
def selector
|
26
|
+
@options[:selector]
|
27
|
+
end
|
28
|
+
def options
|
29
|
+
@options.reject{|key,value| key == :selector}
|
30
|
+
end
|
31
|
+
end
|