splash 0.0.1.alpha → 0.0.1.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/Gemfile +5 -0
  2. data/lib/splash.rb +22 -26
  3. data/lib/splash/acts_as_collection.rb +3 -2
  4. data/lib/splash/acts_as_scope.rb +97 -33
  5. data/lib/splash/acts_as_scope_root.rb +2 -1
  6. data/lib/splash/annotated.rb +2 -1
  7. data/lib/splash/application.rb +2 -1
  8. data/lib/splash/attribute.rb +39 -21
  9. data/lib/splash/attributed_struct.rb +2 -1
  10. data/lib/splash/callbacks.rb +37 -0
  11. data/lib/splash/collection.rb +14 -11
  12. data/lib/splash/connection.rb +2 -1
  13. data/lib/splash/constraint.rb +3 -5
  14. data/lib/splash/constraint/all.rb +2 -1
  15. data/lib/splash/constraint/any.rb +2 -1
  16. data/lib/splash/constraint/in.rb +2 -1
  17. data/lib/splash/constraint/not_nil.rb +2 -1
  18. data/lib/splash/created_at.rb +16 -0
  19. data/lib/splash/document.rb +43 -15
  20. data/lib/splash/embed.rb +29 -9
  21. data/lib/splash/has_attributes.rb +68 -37
  22. data/lib/splash/has_collection.rb +79 -0
  23. data/lib/splash/has_constraint.rb +2 -1
  24. data/lib/splash/map_reduce.rb +124 -0
  25. data/lib/splash/matcher.rb +160 -0
  26. data/lib/splash/namespace.rb +149 -15
  27. data/lib/splash/password.rb +2 -1
  28. data/lib/splash/persister.rb +22 -62
  29. data/lib/splash/query_interface.rb +28 -6
  30. data/lib/splash/saveable.rb +5 -104
  31. data/lib/splash/scope.rb +16 -3
  32. data/lib/splash/scope/map_reduce_interface.rb +33 -0
  33. data/lib/splash/scope/options.rb +16 -6
  34. data/lib/splash/updated_at.rb +15 -0
  35. data/lib/splash/validates.rb +3 -1
  36. data/lib/splash/validator.rb +2 -1
  37. data/lib/splash/writeback.rb +46 -0
  38. data/lib/standart_extensions/array.rb +9 -0
  39. data/lib/standart_extensions/bson.rb +122 -0
  40. data/lib/standart_extensions/class.rb +11 -0
  41. data/lib/{splash/standart_extensions → standart_extensions}/hash.rb +6 -1
  42. data/lib/{splash/standart_extensions → standart_extensions}/module.rb +17 -3
  43. data/lib/standart_extensions/object.rb +13 -0
  44. data/splash.gemspec +17 -0
  45. metadata +20 -16
  46. data/lib/splash/scope_delegator.rb +0 -14
  47. data/lib/splash/scope_options.rb +0 -31
  48. data/lib/splash/standart_extensions/object.rb +0 -11
  49. data/lib/splash/standart_extensions/string.rb +0 -5
  50. data/spec/helper.rb +0 -15
  51. data/spec/lib/annotated_spec.rb +0 -87
  52. data/spec/lib/collection_spec.rb +0 -64
  53. data/spec/lib/has_attributes_spec.rb +0 -43
  54. data/spec/lib/has_constraints_spec.rb +0 -53
  55. data/spec/lib/inheritance_spec.rb +0 -69
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'http://rubygems.org/'
2
+
3
+ gem 'bson_ext'
4
+
5
+ gemspec
data/lib/splash.rb CHANGED
@@ -1,35 +1,31 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  if defined? Splash
2
3
  raise "Splash included twice!"
3
4
  end
4
5
 
6
+ Dir[File.join(File.dirname(__FILE__),"/standart_extensions/*.rb")].each do |path|
7
+ require path
8
+ end
9
+
10
+ class NotGivenClass
11
+ class << self
12
+ def instance
13
+ return (@instance ||= self.new)
14
+ end
15
+ end
16
+ end
17
+ NotGiven = NotGivenClass.instance
18
+ class NotGivenClass
19
+ class << self
20
+ undef :new, :allocate
21
+ end
22
+ end
23
+
5
24
  module Splash
6
25
 
7
- DIR = File.dirname(__FILE__)
8
26
 
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
27
 
32
- end
33
- Dir[Splash::DIR+"/splash/standart_extensions/*.rb"].each do |path|
34
- require path
28
+
29
+ autoload_all File.join(File.dirname(__FILE__),'splash')
30
+
35
31
  end
@@ -1,3 +1,4 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  module Splash::ActsAsCollection
2
3
 
3
4
  include Enumerable
@@ -46,10 +47,10 @@ module Splash::ActsAsCollection
46
47
  end
47
48
 
48
49
  def accepts?(object)
49
- return object === collection_class
50
+ return object.kind_of? collection_class
50
51
  end
51
52
 
52
53
  def include?(object)
53
54
  accepts?(object) && super
54
55
  end
55
- end
56
+ end
@@ -1,6 +1,44 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  module Splash
2
3
  module ActsAsScope
4
+
5
+ module ArraylikeAccess
6
+ def [](*args)
7
+ if args.size == 1
8
+ # range
9
+ if args.first.kind_of? Range
10
+ range = args.first
11
+ offset = range.first.to_int
12
+ last = range.last.to_int
13
+ if last == -1 and !range.exclude_end?
14
+ return query( :skip => offset )
15
+ end
16
+ if last < -1
17
+ raise "ranges with negative ends are not supported ( except -1 for no limit )"
18
+ end
19
+ limit = ( last - offset ) - ( range.exclude_end? ? 1 : 0 )
20
+ return query( :limit => limit, :skip => offset )
21
+ else
22
+ # id query
23
+ return query( :conditions => {'_id'=>args.first} ).first
24
+ end
25
+ elsif args.size == 2
26
+ offset = args[0].to_int
27
+ limit = args[1].to_int
28
+ return query( :limit => limit, :skip => offset )
29
+ end
30
+ raise "bag arguments #{args.inspect}, expected a range or a limit and an offset"
31
+ end
32
+ end
33
+
34
+ module HashlikeAccess
35
+ def [](key)
36
+ return query( :conditions => {'_id'=>key} ).first.value
37
+ end
38
+ end
39
+
3
40
  include QueryInterface
41
+ include Scope::MapReduceInterface
4
42
 
5
43
 
6
44
  # the following methods have to be defined
@@ -26,8 +64,16 @@ module Splash
26
64
  end
27
65
 
28
66
  def each(&block)
29
- self.clone.scope_cursor.each do |o|
30
- yield Saveable.load(o,self)
67
+ a = block.arity
68
+ if a == 1
69
+ self.clone.scope_cursor.each do |o|
70
+ yield Saveable.load(o,self.scope_root)
71
+ end
72
+ elsif a == 2
73
+ self.clone.scope_cursor.each do |o|
74
+ l = Saveable.load(o,self.scope_root)
75
+ yield(l._id,l.value)
76
+ end
31
77
  end
32
78
  self
33
79
  end
@@ -40,6 +86,14 @@ module Splash
40
86
  return result
41
87
  end
42
88
 
89
+ def to_h
90
+ result = {}
91
+ each do |key,value|
92
+ result[key]=value
93
+ end
94
+ return result
95
+ end
96
+
43
97
  def has_next?
44
98
  scope_cursor.has_next?
45
99
  end
@@ -47,11 +101,11 @@ module Splash
47
101
  def next_document
48
102
  nd = scope_cursor.next_document
49
103
  return nil if nd.nil?
50
- return Saveable.load(nd,self)
104
+ return Saveable.load(nd,self.scope_root)
51
105
  end
52
106
 
53
107
  def first
54
- self.clone.limit(1).next_document
108
+ self.limit(1).next_document
55
109
  end
56
110
 
57
111
  def clone
@@ -62,26 +116,6 @@ module Splash
62
116
  scope_cursor.next_document
63
117
  end
64
118
 
65
- def inspect
66
- scope_options.inspect
67
- end
68
-
69
- =begin
70
- def finish!
71
- self.scope_cursor
72
- self
73
- end
74
-
75
- def finished?
76
- !@scope_cursor.nil?
77
- end
78
-
79
- def reset!
80
- self.unset_scope_cursor
81
- self
82
- end
83
- =end
84
-
85
119
  def count
86
120
  self.clone.scope_cursor.count
87
121
  end
@@ -91,15 +125,33 @@ module Splash
91
125
  end
92
126
 
93
127
  def <<(object)
94
- end
95
-
96
- def scoped_methods(*modules,&block)
97
-
128
+ @scope_options.writeback(object)
129
+ if scope_root?
130
+ super(object)
131
+ else
132
+ scope_root.<<(object)
133
+ warn "object #{object} was writen to scope #{self} but won't be findable" unless complies_with?(object)
134
+ return object
135
+ end
98
136
  end
99
137
 
138
+ def complies_with?(object)
139
+ @scope_options.selector.matches?(object)
140
+ end
141
+
142
+ def explain
143
+ self.scope_root.collection.find(*find_options).explain()
144
+ end
145
+
146
+ def update(*args)
147
+ options = find_options
148
+ self.scope_root.collection.update(options[0],*args)
149
+ end
150
+
100
151
  protected
152
+
101
153
  def scope_cursor()
102
- @scope_cursor ||= find!(scope_options.selector,scope_options.options)
154
+ @scope_cursor ||= find!
103
155
  end
104
156
 
105
157
  def unset_scope_cursor()
@@ -110,9 +162,21 @@ module Splash
110
162
  @scope_options = scope_options.merge(options)
111
163
  end
112
164
 
113
- def find!(selector,options)
114
- selector["Type"]=self.scope_root.to_s
115
- self.scope_root.collection.find(selector,options)
165
+ def find!
166
+ self.scope_root.collection.find(*find_options)
116
167
  end
168
+
169
+ def update!(*args)
170
+
171
+ end
172
+
173
+ def find_options
174
+ selector,options = scope_options.selector,scope_options.options
175
+ if self.scope_root.kind_of? Splash::Saveable
176
+ selector["Type"]=self.scope_root.to_s
177
+ end
178
+ return [selector,options]
179
+ end
180
+
117
181
  end
118
- end
182
+ end
@@ -1,3 +1,4 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  module Splash::ActsAsScopeRoot
2
3
  include Splash::ActsAsScope
3
4
 
@@ -7,4 +8,4 @@ module Splash::ActsAsScopeRoot
7
8
  def scope_root?
8
9
  true
9
10
  end
10
- end
11
+ end
@@ -1,3 +1,4 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  module Splash::Annotated
2
3
 
3
4
  class << self
@@ -31,4 +32,4 @@ module Splash::Annotated
31
32
  end
32
33
 
33
34
  end
34
- end
35
+ end
@@ -1,3 +1,4 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  module Splash
2
3
  module Application
3
4
  class << self
@@ -33,4 +34,4 @@ module Splash
33
34
  end
34
35
  end
35
36
  end
36
- end
37
+ end
@@ -1,45 +1,63 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  class Splash::Attribute
2
3
 
3
- include ::Humanized
4
4
  include Splash::HasConstraint
5
5
 
6
- attr_accessor :persister, :type, :default
6
+ NIL_LAMBDA = lambda{ nil }
7
7
 
8
- def initialize(t=nil,&block)
9
- self.type=t if t
8
+ attr_accessor :persister, :type
9
+
10
+ def default(fn=nil,*args,&block)
11
+ if block_given?
12
+ @default_block = block
13
+ elsif !fn.nil?
14
+ @default_block = lambda{ self.send(fn,*args) }
15
+ else
16
+ type.instance_eval &@default_block
17
+ end
18
+ end
19
+
20
+ def initialize(t=Object,&block)
21
+ self.type = t
22
+ @default_block = NIL_LAMBDA
10
23
  instance_eval &block if block_given?
11
24
  end
12
25
 
13
26
  def type= t
14
- @persister = Splash::HasAttributes.get_persister(t)
27
+ @persister = t.persister
15
28
  @type = t
16
29
  end
17
30
 
18
- def persisted_by(*args,&block)
19
- @persister = Splash::HasAttributes.get_persister(*args, &block)
31
+ def persisted_by(p)
32
+ @persister = p
20
33
  end
21
34
 
35
+ # persisting interface
22
36
  def read(value)
23
- return value unless @persister
24
- @persister.read(value)
37
+ @persister.from_saveable(value)
25
38
  end
26
39
 
27
40
  def write(value)
28
- return value unless @persister
29
- @persister.write(value)
41
+ @persister.to_saveable(value)
30
42
  end
31
43
 
32
- def persisted_class
33
- return Object unless @persister
34
- @persister.persisted_class
44
+ # type interface
45
+ def missing
46
+ self.default
35
47
  end
36
48
 
37
- def missing()
38
- if self.default
39
- self.default.clone
40
- else
41
- nil
42
- end
49
+ def writeable?
50
+ true
51
+ end
52
+
53
+ def initial_value
54
+ return type.initial_value if type && type.respond_to?(:initial_value)
55
+ ::NotGiven
56
+ end
57
+
58
+ def before_write(value)
59
+ return type.before_write(value) if type && type.respond_to?(:before_write)
60
+ value
43
61
  end
44
62
 
45
- end
63
+ end
@@ -1,3 +1,4 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  class Splash::AttributedStruct
2
3
 
3
4
  include Splash::HasAttributes
@@ -5,4 +6,4 @@ class Splash::AttributedStruct
5
6
  def initialize(attr={})
6
7
  self.attributes.load(attr)
7
8
  end
8
- end
9
+ end
@@ -0,0 +1,37 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Splash::Callbacks
3
+
4
+ protected
5
+ def run_callbacks(name,*args)
6
+ regex = Regexp.new("^#{Regexp.escape name.to_s}"_)
7
+ self.methods.each do |meth|
8
+ if meth.to_s ~= regex
9
+ self.send(meth,*args)
10
+ end
11
+ end
12
+ end
13
+
14
+ def with_callbacks(name,*args)
15
+ run_callbacks('before_' + name.to_s,*args)
16
+ result = yield
17
+ run_callbacks('after_' + name.to_s,*args)
18
+ return result
19
+ end
20
+
21
+ module ClassMethods
22
+
23
+ def with_callbacks(fn)
24
+ def ___callbacked()
25
+
26
+ end
27
+ alias_method(fn +'_without_callbacks',fn)
28
+
29
+ self.define_method(fn+'_with_callback') do
30
+ fn
31
+ end
32
+ end
33
+
34
+ define_annotation :with_callbacks
35
+
36
+
37
+ end
@@ -1,3 +1,4 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  class Splash::Collection < Array
2
3
  include Splash::ActsAsCollection
3
4
 
@@ -17,36 +18,38 @@ class Splash::Collection < Array
17
18
  end
18
19
 
19
20
 
20
- class Persister < Splash::Persister
21
+ class Persister
21
22
 
22
- def read(val)
23
+ attr_accessor :entry_persister
24
+
25
+ def from_saveable(val)
23
26
  return nil if val.nil?
24
- nu=persisted_class.new
27
+ nu=@base_class.new
25
28
  val.inject(nu){|memo,e|
26
- memo << @persister.read(e)
29
+ memo << @entry_persister.from_saveable(e)
27
30
  memo
28
31
  }
29
32
  end
30
33
 
31
- def write(val)
34
+ def to_saveable(val)
32
35
  return nil if val.nil?
33
36
  val.inject([]){|memo,e|
34
- memo << @persister.write(e)
37
+ memo << @entry_persister.to_saveable(e)
35
38
  memo
36
39
  }
37
40
  end
38
41
 
39
- def persist_class(col)
40
- @persister=Splash::HasAttributes.get_persister(col.collection_class)
41
- super
42
+ def initialize(klass, entry_persister)
43
+ @base_class = klass
44
+ @entry_persister = entry_persister
42
45
  end
43
46
 
44
47
  end
45
48
 
46
49
  class << self
47
50
  def persister
48
- return Splash::Collection::Persister
51
+ return Splash::Collection::Persister.new(self, @collection_class.persister)
49
52
  end
50
53
  end
51
54
 
52
- end
55
+ end