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,45 @@
|
|
1
|
+
require File.join File.dirname(__FILE__), "object"
|
2
|
+
require File.join File.dirname(__FILE__), "module"
|
3
|
+
class Hash
|
4
|
+
|
5
|
+
DEEP_MERGER=proc{|key,value,value2|
|
6
|
+
if( value.kind_of?(Hash) && value2.kind_of?(Hash) )
|
7
|
+
value.merge(value2,&DEEP_MERGER)
|
8
|
+
else
|
9
|
+
value2
|
10
|
+
end
|
11
|
+
}
|
12
|
+
|
13
|
+
def deep_merge(k)
|
14
|
+
return self if k.nil?
|
15
|
+
merge(k,&DEEP_MERGER)
|
16
|
+
end
|
17
|
+
|
18
|
+
def deep_merge!(k)
|
19
|
+
return self if k.nil?
|
20
|
+
merge!(k,&DEEP_MERGER)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_saveable
|
24
|
+
return self.inject({}) do |h,(k,v)|
|
25
|
+
h[k]=Splash::Saveable.to_saveable(v);
|
26
|
+
h
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def only(keys)
|
31
|
+
self.reject{|key,val| !keys.include? key}
|
32
|
+
end
|
33
|
+
|
34
|
+
def hashmap
|
35
|
+
self.inject({}) do |newhash, (k,v)|
|
36
|
+
newhash[k] = yield(k, v)
|
37
|
+
newhash
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def +(hsh)
|
42
|
+
self.merge(hsh)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class Module
|
2
|
+
|
3
|
+
def persister
|
4
|
+
@persister ||= Splash::Persister
|
5
|
+
end
|
6
|
+
|
7
|
+
def persister=(p)
|
8
|
+
@persister=p
|
9
|
+
end
|
10
|
+
|
11
|
+
def named?
|
12
|
+
to_s[0..1]!="#<"
|
13
|
+
end
|
14
|
+
|
15
|
+
def define_annotation(name)
|
16
|
+
self.class_eval <<-DEF,__FILE__, __LINE__
|
17
|
+
alias_method #{(name.to_s+"!").to_sym.inspect}, #{name.inspect}
|
18
|
+
def #{name.to_s}(*args,&block)
|
19
|
+
@annotations ||= []
|
20
|
+
@annotations << [#{(name.to_s+"!").to_sym.inspect},args,block]
|
21
|
+
end
|
22
|
+
DEF
|
23
|
+
end
|
24
|
+
|
25
|
+
def merged_inheritable_attr(name,default=[],&block)
|
26
|
+
if block_given?
|
27
|
+
merger = lambda &block
|
28
|
+
else
|
29
|
+
merger = lambda{|a,b| a if b.nil?; a + b }
|
30
|
+
end
|
31
|
+
|
32
|
+
self.instance_eval do
|
33
|
+
|
34
|
+
@merged_inheritable_attr_info ||={}
|
35
|
+
|
36
|
+
@merged_inheritable_attr_info[name] = {:default=>default,:merger => merger }
|
37
|
+
|
38
|
+
def self.merged_inheritable_attr_info(name)
|
39
|
+
if @merged_inheritable_attr_info && @merged_inheritable_attr_info.key?(name)
|
40
|
+
return @merged_inheritable_attr_info[name]
|
41
|
+
end
|
42
|
+
superclass.merged_inheritable_attr_info(name) if superclass.respond_to?(:merged_inheritable_attr_info)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
self.instance_eval <<-DEF,__FILE__, __LINE__
|
50
|
+
def #{name.to_s}
|
51
|
+
@#{name.to_s} ||= merged_inheritable_attr_info(#{name.inspect})[:default].dup
|
52
|
+
end
|
53
|
+
def #{name.to_s}=(v)
|
54
|
+
@#{name.to_s}=v
|
55
|
+
end
|
56
|
+
def all_#{name.to_s}
|
57
|
+
unless superclass.respond_to? :all_#{name.to_s}
|
58
|
+
return #{name.to_s}
|
59
|
+
end
|
60
|
+
merged_inheritable_attr_info(#{name.inspect})[:merger].call(#{name.to_s},superclass.all_#{name.to_s})
|
61
|
+
end
|
62
|
+
def each_#{name.to_s}
|
63
|
+
c=self
|
64
|
+
begin
|
65
|
+
yield(c.#{name.to_s})
|
66
|
+
c=c.superclass
|
67
|
+
end while(c.respond_to? #{name.to_sym.inspect})
|
68
|
+
end
|
69
|
+
|
70
|
+
DEF
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "set"
|
2
|
+
module Splash::Validates
|
3
|
+
|
4
|
+
class Invalid < Exception
|
5
|
+
|
6
|
+
attr_reader :object, :validators
|
7
|
+
|
8
|
+
def initialize(obj)
|
9
|
+
super
|
10
|
+
self.object = obj
|
11
|
+
self.validators = Set.new
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def included(base)
|
18
|
+
base.instance_eval do
|
19
|
+
merged_inheritable_attr :validators,Set.new
|
20
|
+
end
|
21
|
+
base.extend(ClassMethods)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module ClassMethods
|
26
|
+
def validate(*args,&block)
|
27
|
+
if args.first.respond_to? :valid?
|
28
|
+
validators << validator
|
29
|
+
end
|
30
|
+
validators << Splash::Validator.new(*args,&block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def valid?
|
35
|
+
validators = self.class.all_validators
|
36
|
+
|
37
|
+
validators.sort! do |a,b|
|
38
|
+
if b.depends.include? a.field
|
39
|
+
-1
|
40
|
+
elsif a.depends.include? b.field
|
41
|
+
1
|
42
|
+
else
|
43
|
+
0
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
return validators.all? do |validator|
|
48
|
+
validator.valid?(self)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def raise_if_invalid
|
53
|
+
v = Invalid.new(self)
|
54
|
+
|
55
|
+
validators = self.class.all_validators
|
56
|
+
|
57
|
+
validators.sort! do |a,b|
|
58
|
+
if b.depends.include? a.field
|
59
|
+
-1
|
60
|
+
elsif a.depends.include? b.field
|
61
|
+
1
|
62
|
+
else
|
63
|
+
0
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
validators.each do |validator|
|
68
|
+
v.validators << validator unless validator.valid?(self)
|
69
|
+
end
|
70
|
+
|
71
|
+
raise v if v.validators.size > 0
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Splash::Validator
|
2
|
+
|
3
|
+
attr_reader :field,:block,:description,:depends
|
4
|
+
|
5
|
+
def valid?(object)
|
6
|
+
if @block
|
7
|
+
return @block.call(object)
|
8
|
+
else
|
9
|
+
value = object.send(@field)
|
10
|
+
if value.respond_to? :valid?
|
11
|
+
return value.valid?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(field, description,options={},&block)
|
18
|
+
@field = field
|
19
|
+
@block = block
|
20
|
+
@description = description
|
21
|
+
@depends = (options[:depends] || Set.new)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/splash.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
if defined? Splash
|
2
|
+
raise "Splash included twice!"
|
3
|
+
end
|
4
|
+
|
5
|
+
module Splash
|
6
|
+
|
7
|
+
DIR = File.dirname(__FILE__)
|
8
|
+
|
9
|
+
autoload :ActsAsCollection,DIR+"/splash/acts_as_collection"
|
10
|
+
autoload :ActsAsScope,DIR+"/splash/acts_as_scope"
|
11
|
+
autoload :ActsAsScopeRoot,DIR+"/splash/acts_as_scope_root"
|
12
|
+
autoload :Annotated,DIR+"/splash/annotated"
|
13
|
+
autoload :Scope,DIR+"/splash/scope"
|
14
|
+
autoload :Entity,DIR+"/splash/entity"
|
15
|
+
autoload :Validates,DIR+"/splash/validates"
|
16
|
+
autoload :Saveable,DIR+"/splash/saveable"
|
17
|
+
autoload :HasAttributes,DIR+"/splash/has_attributes"
|
18
|
+
autoload :NameSpace,DIR+"/splash/namespace"
|
19
|
+
autoload :Persister, DIR+"/splash/persister"
|
20
|
+
autoload :Lazy,DIR+"/splash/lazy"
|
21
|
+
autoload :QueryInterface,DIR+"/splash/query_interface"
|
22
|
+
autoload :Embed,DIR+"/splash/embed"
|
23
|
+
autoload :Document,DIR+"/splash/document"
|
24
|
+
autoload :Collection,DIR+"/splash/collection"
|
25
|
+
autoload :ScopeDelegator,DIR+"/splash/scope_delegator"
|
26
|
+
autoload :Attribute, DIR+"/splash/attribute"
|
27
|
+
autoload :HasConstraint, DIR+"/splash/has_constraint"
|
28
|
+
autoload :Constraint, DIR+"/splash/constraint"
|
29
|
+
autoload :AttributedStruct, DIR+"/splash/attributed_struct"
|
30
|
+
autoload :Password, DIR+"/splash/password"
|
31
|
+
|
32
|
+
end
|
33
|
+
Dir[Splash::DIR+"/splash/standart_extensions/*.rb"].each do |path|
|
34
|
+
require path
|
35
|
+
end
|
data/spec/helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
gem "mongo"
|
3
|
+
require "mongo"
|
4
|
+
|
5
|
+
require File.join(File.dirname(__FILE__),"../../Humanized/lib/humanized")
|
6
|
+
|
7
|
+
culture=Humanized::Culture.new
|
8
|
+
culture.default_case = :nominativ
|
9
|
+
culture.converter = Humanized::Converter.new({})
|
10
|
+
|
11
|
+
|
12
|
+
Humanized::Culture.native=culture
|
13
|
+
Humanized::Culture.current=culture
|
14
|
+
|
15
|
+
require File.join(File.dirname(__FILE__),"../lib/splash")
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"../helper")
|
2
|
+
|
3
|
+
describe Splash::Annotated do
|
4
|
+
|
5
|
+
it "should work for modules" do
|
6
|
+
|
7
|
+
module NameAnnotations
|
8
|
+
|
9
|
+
include Splash::Annotated
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def included(base)
|
13
|
+
base.extend(ClassMethods)
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
|
20
|
+
def named(fn,name)
|
21
|
+
@named||={}
|
22
|
+
@named[fn]=name
|
23
|
+
end
|
24
|
+
|
25
|
+
def name(fn)
|
26
|
+
return @named[fn] rescue nil
|
27
|
+
end
|
28
|
+
|
29
|
+
define_annotation :named
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class ClassWithSimpleAnnotations
|
35
|
+
|
36
|
+
include NameAnnotations
|
37
|
+
|
38
|
+
named "Nice Function!"
|
39
|
+
def nice
|
40
|
+
return 42
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
ClassWithSimpleAnnotations.name(:nice).should == "Nice Function!"
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should work for classes" do
|
50
|
+
|
51
|
+
class AnnotatedParent
|
52
|
+
|
53
|
+
include Splash::Annotated
|
54
|
+
|
55
|
+
class << self
|
56
|
+
|
57
|
+
def named(fn,name)
|
58
|
+
@named||={}
|
59
|
+
@named[fn]=name
|
60
|
+
end
|
61
|
+
|
62
|
+
def name(fn)
|
63
|
+
return @named[fn] rescue nil
|
64
|
+
end
|
65
|
+
|
66
|
+
define_annotation :named
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
class Child < AnnotatedParent
|
73
|
+
|
74
|
+
include NameAnnotations
|
75
|
+
|
76
|
+
named "Nice Function!"
|
77
|
+
def nice
|
78
|
+
return 42
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
Child.name(:nice).should == "Nice Function!"
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"../helper")
|
2
|
+
|
3
|
+
describe Splash::ActsAsCollection do
|
4
|
+
|
5
|
+
it "should support class integration" do
|
6
|
+
|
7
|
+
class Friend
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
class FriendList < Array
|
12
|
+
|
13
|
+
include Splash::ActsAsCollection.of(Friend)
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
FriendList.should < Splash::ActsAsCollection
|
18
|
+
|
19
|
+
fl = FriendList.new
|
20
|
+
|
21
|
+
fl.respond_to?(:create).should be_true
|
22
|
+
|
23
|
+
fl.create
|
24
|
+
|
25
|
+
fl.should have(1).item
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should support the collection class" do
|
30
|
+
|
31
|
+
class Friend
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
fl = Splash::Collection.of(Friend).new
|
36
|
+
|
37
|
+
fl.respond_to?(:create).should be_true
|
38
|
+
|
39
|
+
fl.create
|
40
|
+
|
41
|
+
fl.should have(1).item
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should support comparison" do
|
46
|
+
|
47
|
+
|
48
|
+
class User
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
class Admin < User
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
fl = Splash::Collection.of(User).new
|
57
|
+
|
58
|
+
fl.should be_a(Splash::Collection.of(User))
|
59
|
+
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"../helper")
|
2
|
+
|
3
|
+
describe Splash::HasAttributes do
|
4
|
+
|
5
|
+
describe "declaration" do
|
6
|
+
|
7
|
+
it "should look cool and work" do
|
8
|
+
|
9
|
+
class User
|
10
|
+
|
11
|
+
include Splash::HasAttributes
|
12
|
+
|
13
|
+
|
14
|
+
# simple style
|
15
|
+
def_attribute 'name'
|
16
|
+
|
17
|
+
# simple with type
|
18
|
+
def_attribute 'friends', Splash::Collection.of(User)
|
19
|
+
|
20
|
+
def_attribute( 'mails', Splash::Collection.of(String)) do
|
21
|
+
|
22
|
+
self.default = Splash::Collection.of(String).new
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
User.attributes.should have(3).items
|
29
|
+
|
30
|
+
u = User.new
|
31
|
+
|
32
|
+
u.name.should be_nil
|
33
|
+
|
34
|
+
u.friends.should be_nil
|
35
|
+
|
36
|
+
u.mails.should_not be_nil
|
37
|
+
u.mails.should be_a(Splash::Collection.of(String))
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"../helper")
|
2
|
+
|
3
|
+
describe Splash::HasConstraint do
|
4
|
+
|
5
|
+
describe "declaration" do
|
6
|
+
|
7
|
+
it "should work in a trivial case" do
|
8
|
+
|
9
|
+
class Field
|
10
|
+
|
11
|
+
include Splash::HasConstraint
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
f = Field.new
|
16
|
+
|
17
|
+
f.constraint.should_not be_nil
|
18
|
+
|
19
|
+
f.constraint.accept?(nil).should be_true
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should give the power to write simple constraints fast" do
|
24
|
+
|
25
|
+
class Field
|
26
|
+
|
27
|
+
include Splash::HasConstraint
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
f = Field.new
|
32
|
+
|
33
|
+
f.constraint.create "should not be nil" do |value|
|
34
|
+
!value.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
f.constraint.create "should be a string with 5 to 10 chars" do |value|
|
38
|
+
value.kind_of?(String) && (5..10).include?(value.length)
|
39
|
+
end
|
40
|
+
|
41
|
+
f.constraint.should have(2).items
|
42
|
+
|
43
|
+
f.constraint.accept?(nil).should be_false
|
44
|
+
|
45
|
+
f.constraint.accept?("aaa").should be_false
|
46
|
+
|
47
|
+
f.constraint.accept?("aaaaa").should be_true
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"../helper")
|
2
|
+
|
3
|
+
describe "inheritance" do
|
4
|
+
|
5
|
+
it "should generate normal methods" do
|
6
|
+
|
7
|
+
class A
|
8
|
+
|
9
|
+
merged_inheritable_attr :a
|
10
|
+
merged_inheritable_attr :b,"b"
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
A.respond_to?(:a).should be_true
|
15
|
+
A.respond_to?(:b).should be_true
|
16
|
+
|
17
|
+
A.b.should == "b"
|
18
|
+
|
19
|
+
A.all_b.should == "b"
|
20
|
+
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should generate inheritable methods" do
|
25
|
+
|
26
|
+
class A
|
27
|
+
|
28
|
+
merged_inheritable_attr :a
|
29
|
+
merged_inheritable_attr :b,"b" do |a,b|
|
30
|
+
a + b
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
class B < A
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
class C < B
|
40
|
+
merged_inheritable_attr :c
|
41
|
+
end
|
42
|
+
|
43
|
+
A.a << 1
|
44
|
+
|
45
|
+
B.respond_to?(:a).should be_true
|
46
|
+
B.respond_to?(:b).should be_true
|
47
|
+
|
48
|
+
B.b = "c"
|
49
|
+
|
50
|
+
B.a << 2
|
51
|
+
|
52
|
+
B.all_b.should == "cb"
|
53
|
+
|
54
|
+
C.all_b.should == "bcb"
|
55
|
+
|
56
|
+
C.a << 3
|
57
|
+
|
58
|
+
A.a.should have(1).item
|
59
|
+
A.all_a.should have(1).item
|
60
|
+
|
61
|
+
B.a.should have(1).item
|
62
|
+
B.all_a.should have(2).items
|
63
|
+
|
64
|
+
C.a.should have(1).item
|
65
|
+
C.all_a.should have(3).items
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|