splash 0.0.1.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/Rakefile +19 -0
  2. data/lib/splash/acts_as_collection.rb +55 -0
  3. data/lib/splash/acts_as_scope.rb +118 -0
  4. data/lib/splash/acts_as_scope_root.rb +10 -0
  5. data/lib/splash/annotated.rb +34 -0
  6. data/lib/splash/application.rb +36 -0
  7. data/lib/splash/attribute.rb +45 -0
  8. data/lib/splash/attributed_struct.rb +8 -0
  9. data/lib/splash/collection.rb +52 -0
  10. data/lib/splash/connection.rb +26 -0
  11. data/lib/splash/constraint/all.rb +24 -0
  12. data/lib/splash/constraint/any.rb +13 -0
  13. data/lib/splash/constraint/in.rb +13 -0
  14. data/lib/splash/constraint/not_nil.rb +9 -0
  15. data/lib/splash/constraint.rb +62 -0
  16. data/lib/splash/document.rb +38 -0
  17. data/lib/splash/embed.rb +37 -0
  18. data/lib/splash/has_attributes.rb +146 -0
  19. data/lib/splash/has_constraint.rb +9 -0
  20. data/lib/splash/namespace.rb +67 -0
  21. data/lib/splash/password.rb +31 -0
  22. data/lib/splash/persister.rb +66 -0
  23. data/lib/splash/query_interface.rb +84 -0
  24. data/lib/splash/saveable.rb +141 -0
  25. data/lib/splash/scope/options.rb +58 -0
  26. data/lib/splash/scope.rb +46 -0
  27. data/lib/splash/scope_delegator.rb +14 -0
  28. data/lib/splash/scope_options.rb +31 -0
  29. data/lib/splash/standart_extensions/hash.rb +45 -0
  30. data/lib/splash/standart_extensions/module.rb +73 -0
  31. data/lib/splash/standart_extensions/object.rb +11 -0
  32. data/lib/splash/standart_extensions/string.rb +5 -0
  33. data/lib/splash/validates.rb +75 -0
  34. data/lib/splash/validator.rb +24 -0
  35. data/lib/splash.rb +35 -0
  36. data/spec/helper.rb +15 -0
  37. data/spec/lib/annotated_spec.rb +87 -0
  38. data/spec/lib/collection_spec.rb +64 -0
  39. data/spec/lib/has_attributes_spec.rb +43 -0
  40. data/spec/lib/has_constraints_spec.rb +53 -0
  41. data/spec/lib/inheritance_spec.rb +69 -0
  42. 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,11 @@
1
+ class Object
2
+
3
+ def to_bson
4
+ self
5
+ end
6
+
7
+ def persister
8
+ Splash::Persister
9
+ end
10
+
11
+ end
@@ -0,0 +1,5 @@
1
+ class String
2
+ def to_bson
3
+ BSON::ObjectID.from_string(self)
4
+ end
5
+ 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