splash 0.0.1.alpha
Sign up to get free protection for your applications and to get access to all the features.
- 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
|