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.
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