simply_stored 0.1.4

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 (121) hide show
  1. data/lib/simply_stored/class_methods_base.rb +31 -0
  2. data/lib/simply_stored/couch/belongs_to.rb +117 -0
  3. data/lib/simply_stored/couch/ext/couch_potato.rb +16 -0
  4. data/lib/simply_stored/couch/has_many.rb +148 -0
  5. data/lib/simply_stored/couch/has_one.rb +93 -0
  6. data/lib/simply_stored/couch/validations.rb +74 -0
  7. data/lib/simply_stored/couch/views/array_property_view_spec.rb +22 -0
  8. data/lib/simply_stored/couch/views.rb +1 -0
  9. data/lib/simply_stored/couch.rb +278 -0
  10. data/lib/simply_stored/instance_methods.rb +143 -0
  11. data/lib/simply_stored/simpledb/associations.rb +196 -0
  12. data/lib/simply_stored/simpledb/attributes.rb +173 -0
  13. data/lib/simply_stored/simpledb/storag.rb +85 -0
  14. data/lib/simply_stored/simpledb/validations.rb +88 -0
  15. data/lib/simply_stored/simpledb.rb +212 -0
  16. data/lib/simply_stored/storage.rb +93 -0
  17. data/lib/simply_stored.rb +9 -0
  18. data/test/custom_views_test.rb +33 -0
  19. data/test/fixtures/couch.rb +182 -0
  20. data/test/fixtures/simpledb/item.rb +11 -0
  21. data/test/fixtures/simpledb/item_daddy.rb +8 -0
  22. data/test/fixtures/simpledb/log_item.rb +3 -0
  23. data/test/fixtures/simpledb/namespace_bar.rb +5 -0
  24. data/test/fixtures/simpledb/namespace_foo.rb +7 -0
  25. data/test/fixtures/simpledb/protected_item.rb +3 -0
  26. data/test/simply_stored_couch_test.rb +1684 -0
  27. data/test/simply_stored_simpledb_test.rb +1341 -0
  28. data/test/test_helper.rb +22 -0
  29. data/test/vendor/dhaka-2.2.1/lib/dhaka/dot/dot.rb +29 -0
  30. data/test/vendor/dhaka-2.2.1/lib/dhaka/evaluator/evaluator.rb +133 -0
  31. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/closure_hash.rb +15 -0
  32. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/grammar.rb +240 -0
  33. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/grammar_symbol.rb +27 -0
  34. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/precedence.rb +19 -0
  35. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/production.rb +36 -0
  36. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/accept_actions.rb +36 -0
  37. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/alphabet.rb +21 -0
  38. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/compiled_lexer.rb +46 -0
  39. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/dfa.rb +121 -0
  40. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/lexeme.rb +32 -0
  41. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/lexer.rb +70 -0
  42. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/lexer_run.rb +78 -0
  43. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/regex_grammar.rb +392 -0
  44. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/regex_parser.rb +2010 -0
  45. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/regex_tokenizer.rb +14 -0
  46. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/specification.rb +96 -0
  47. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/state.rb +68 -0
  48. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/state_machine.rb +37 -0
  49. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/action.rb +55 -0
  50. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/channel.rb +58 -0
  51. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/compiled_parser.rb +51 -0
  52. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/conflict.rb +54 -0
  53. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/item.rb +42 -0
  54. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parse_result.rb +50 -0
  55. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parse_tree.rb +66 -0
  56. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parser.rb +165 -0
  57. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parser_methods.rb +11 -0
  58. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parser_run.rb +39 -0
  59. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parser_state.rb +74 -0
  60. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/token.rb +22 -0
  61. data/test/vendor/dhaka-2.2.1/lib/dhaka/runtime.rb +51 -0
  62. data/test/vendor/dhaka-2.2.1/lib/dhaka/tokenizer/tokenizer.rb +190 -0
  63. data/test/vendor/dhaka-2.2.1/lib/dhaka.rb +62 -0
  64. data/test/vendor/dhaka-2.2.1/test/all_tests.rb +5 -0
  65. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_evaluator.rb +64 -0
  66. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_evaluator_test.rb +43 -0
  67. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_grammar.rb +41 -0
  68. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_grammar_test.rb +9 -0
  69. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_test_methods.rb +9 -0
  70. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_tokenizer.rb +39 -0
  71. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_tokenizer_test.rb +38 -0
  72. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_evaluator.rb +43 -0
  73. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_grammar.rb +24 -0
  74. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_grammar_test.rb +30 -0
  75. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_lexer_specification.rb +23 -0
  76. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_parser_test.rb +33 -0
  77. data/test/vendor/dhaka-2.2.1/test/brackets/bracket_grammar.rb +23 -0
  78. data/test/vendor/dhaka-2.2.1/test/brackets/bracket_tokenizer.rb +22 -0
  79. data/test/vendor/dhaka-2.2.1/test/brackets/brackets_test.rb +28 -0
  80. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_driver.rb +46 -0
  81. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_driver_test.rb +276 -0
  82. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_evaluator.rb +284 -0
  83. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_evaluator_test.rb +38 -0
  84. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_grammar.rb +104 -0
  85. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_lexer.rb +109 -0
  86. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_lexer_specification.rb +37 -0
  87. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_lexer_test.rb +58 -0
  88. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_parser.rb +879 -0
  89. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_parser_test.rb +55 -0
  90. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_test.rb +170 -0
  91. data/test/vendor/dhaka-2.2.1/test/core/another_lalr_but_not_slr_grammar.rb +20 -0
  92. data/test/vendor/dhaka-2.2.1/test/core/compiled_parser_test.rb +44 -0
  93. data/test/vendor/dhaka-2.2.1/test/core/dfa_test.rb +170 -0
  94. data/test/vendor/dhaka-2.2.1/test/core/evaluator_test.rb +22 -0
  95. data/test/vendor/dhaka-2.2.1/test/core/grammar_test.rb +83 -0
  96. data/test/vendor/dhaka-2.2.1/test/core/lalr_but_not_slr_grammar.rb +19 -0
  97. data/test/vendor/dhaka-2.2.1/test/core/lexer_test.rb +139 -0
  98. data/test/vendor/dhaka-2.2.1/test/core/malformed_grammar.rb +7 -0
  99. data/test/vendor/dhaka-2.2.1/test/core/malformed_grammar_test.rb +8 -0
  100. data/test/vendor/dhaka-2.2.1/test/core/nullable_grammar.rb +21 -0
  101. data/test/vendor/dhaka-2.2.1/test/core/parse_result_test.rb +44 -0
  102. data/test/vendor/dhaka-2.2.1/test/core/parser_state_test.rb +24 -0
  103. data/test/vendor/dhaka-2.2.1/test/core/parser_test.rb +131 -0
  104. data/test/vendor/dhaka-2.2.1/test/core/precedence_grammar.rb +17 -0
  105. data/test/vendor/dhaka-2.2.1/test/core/precedence_grammar_test.rb +9 -0
  106. data/test/vendor/dhaka-2.2.1/test/core/rr_conflict_grammar.rb +21 -0
  107. data/test/vendor/dhaka-2.2.1/test/core/simple_grammar.rb +22 -0
  108. data/test/vendor/dhaka-2.2.1/test/core/sr_conflict_grammar.rb +16 -0
  109. data/test/vendor/dhaka-2.2.1/test/dhaka_test_helper.rb +17 -0
  110. data/test/vendor/dhaka-2.2.1/test/fake_logger.rb +17 -0
  111. data/test/vendor/simplerdb-0.2/lib/simplerdb/client_exception.rb +10 -0
  112. data/test/vendor/simplerdb-0.2/lib/simplerdb/db.rb +146 -0
  113. data/test/vendor/simplerdb-0.2/lib/simplerdb/query_language.rb +266 -0
  114. data/test/vendor/simplerdb-0.2/lib/simplerdb/server.rb +33 -0
  115. data/test/vendor/simplerdb-0.2/lib/simplerdb/servlet.rb +191 -0
  116. data/test/vendor/simplerdb-0.2/lib/simplerdb.rb +3 -0
  117. data/test/vendor/simplerdb-0.2/test/functional_test.rb +81 -0
  118. data/test/vendor/simplerdb-0.2/test/query_evaluator_test.rb +73 -0
  119. data/test/vendor/simplerdb-0.2/test/query_parser_test.rb +64 -0
  120. data/test/vendor/simplerdb-0.2/test/simplerdb_test.rb +80 -0
  121. metadata +182 -0
@@ -0,0 +1,31 @@
1
+ module SimplyStored
2
+ module ClassMethods
3
+ module Base
4
+ def get_class_from_name(klass_name)
5
+ klass_name.to_s.gsub('__','/').gsub('__','::').classify.constantize
6
+ end
7
+
8
+ def foreign_key
9
+ name.underscore.gsub('/','__').gsub('::','__') + "_id"
10
+ end
11
+
12
+ def foreign_property
13
+ name.underscore.gsub('/','__').gsub('::','__')
14
+ end
15
+
16
+ def attr_protected(*args)
17
+ @_protected_attributes ||= []
18
+ @_protected_attributes += args.to_a
19
+ end
20
+
21
+ def attr_accessible(*args)
22
+ @_accessible_attributes ||= []
23
+ @_accessible_attributes += args.to_a
24
+ end
25
+
26
+ def _find_property(name)
27
+ properties.find{|property| property.name == name}
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,117 @@
1
+ # Gracefully taken from CouchPotato after it has been removed for good.
2
+ module SimplyStored
3
+ module Couch
4
+ module BelongsTo
5
+
6
+ def belongs_to(name)
7
+ map_definition_without_deleted = <<-eos
8
+ function(doc) {
9
+ if (doc['ruby_class'] == '#{self.to_s}' && doc['#{name.to_s}_id'] != null) {
10
+ if (doc['#{soft_delete_attribute}'] && doc['#{soft_delete_attribute}'] != null){
11
+ // "soft" deleted
12
+ }else{
13
+ emit(doc.#{name.to_s}_id, null);
14
+ }
15
+ }
16
+ }
17
+ eos
18
+
19
+ view "association_#{self.name.underscore}_belongs_to_#{name}",
20
+ :map => map_definition_without_deleted,
21
+ :type => "custom",
22
+ :include_docs => true
23
+
24
+ map_definition_with_deleted = <<-eos
25
+ function(doc) {
26
+ if (doc['ruby_class'] == '#{self.to_s}' && doc['#{name.to_s}_id'] != null) {
27
+ emit(doc.#{name.to_s}_id, null);
28
+ }
29
+ }
30
+ eos
31
+
32
+ view "association_#{self.name.underscore}_belongs_to_#{name}_with_deleted",
33
+ :map => map_definition_with_deleted,
34
+ :type => "custom",
35
+ :include_docs => true
36
+
37
+ property name, :class => SimplyStored::Couch::BelongsTo::Property
38
+ end
39
+
40
+ class Property #:nodoc:
41
+ attr_accessor :name, :options
42
+
43
+ def initialize(owner_clazz, name, options = {})
44
+ @name, @options = name, options
45
+ item_class_name = self.item_class_name
46
+ owner_clazz.class_eval do
47
+ attr_reader "#{name}_id"
48
+ attr_accessor "#{name}_id_was"
49
+
50
+ define_method name do |*args|
51
+ options = args.last.is_a?(Hash) ? args.last : {}
52
+ options.assert_valid_keys(:force_reload, :with_deleted)
53
+ forced_reload = options[:force_reload] || false
54
+ with_deleted = options[:with_deleted] || false
55
+
56
+ return instance_variable_get("@#{name}") unless instance_variable_get("@#{name}").nil? or forced_reload
57
+ instance_variable_set("@#{name}", send("#{name}_id") ? Object.const_get(item_class_name).find(send("#{name}_id"), :with_deleted => with_deleted) : nil)
58
+ end
59
+
60
+ define_method "#{name}=" do |value|
61
+ klass = self.class.get_class_from_name(name)
62
+ raise ArgumentError, "expected #{klass} got #{value.class}" unless value.nil? || value.is_a?(klass)
63
+
64
+ instance_variable_set("@#{name}", value)
65
+ if value.nil?
66
+ instance_variable_set("@#{name}_id", nil)
67
+ else
68
+ instance_variable_set("@#{name}_id", value.id)
69
+ end
70
+ end
71
+
72
+ define_method "#{name}_id=" do |id|
73
+ remove_instance_variable("@#{name}") if instance_variable_defined?("@#{name}")
74
+ instance_variable_set("@#{name}_id", id)
75
+ end
76
+
77
+ define_method "#{name}_changed?" do
78
+ self.send("#{name}_id") != self.send("#{name}_id_was")
79
+ end
80
+ end
81
+ end
82
+
83
+ def save(object)
84
+ end
85
+
86
+ def dirty?(object)
87
+ object.send("#{name}_id_was") != object.send("#{name}_id")
88
+ end
89
+
90
+ def reset_dirty_attribute(object)
91
+ object.send("#{name}_id_was=", object.send("#{name}_id"))
92
+ end
93
+
94
+ def destroy(object)
95
+
96
+ end
97
+
98
+ def build(object, json)
99
+ object.send "#{name}_id=", json["#{name}_id"]
100
+ object.send "#{name}_id_was=", json["#{name}_id"]
101
+ end
102
+
103
+ def serialize(json, object)
104
+ json["#{name}_id"] = object.send("#{name}_id") if object.send("#{name}_id")
105
+ end
106
+
107
+ def item_class_name
108
+ @name.to_s.camelize
109
+ end
110
+
111
+ def association?
112
+ true
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,16 @@
1
+ module CouchPotato
2
+ module Persistence
3
+ module DirtyAttributes
4
+ private
5
+
6
+ def reset_dirty_attributes
7
+ self.class.properties.each do |property|
8
+ if !property.respond_to?(:supports_dirty?) || property.supports_dirty?
9
+ property.respond_to?(:reset_dirty_attribute) ? property.reset_dirty_attribute(self) :
10
+ instance_variable_set("@#{property.name}_was", send(property.name))
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,148 @@
1
+ module SimplyStored
2
+ module Couch
3
+ module HasMany
4
+ def has_many(name, options = {})
5
+ property name, options.merge(:class => SimplyStored::Couch::HasMany::Property)
6
+ end
7
+
8
+ def define_has_many_getter(name)
9
+ define_method(name) do |*args|
10
+ options = args.first && args.first.is_a?(Hash) && args.first
11
+ if options
12
+ options.assert_valid_keys(:force_reload, :with_deleted)
13
+ forced_reload = options[:force_reload]
14
+ with_deleted = options[:with_deleted]
15
+ else
16
+ forced_reload = false
17
+ with_deleted = false
18
+ end
19
+
20
+ if forced_reload || instance_variable_get("@#{name}").nil?
21
+ instance_variable_set("@#{name}", find_associated(name, self.class, :with_deleted => with_deleted))
22
+ end
23
+ instance_variable_get("@#{name}")
24
+ end
25
+ end
26
+
27
+ def define_has_many_through_getter(name, through)
28
+ raise ArgumentError, "no such relation: #{self} - #{through}" unless instance_methods.map(&:to_sym).include?(through.to_sym)
29
+
30
+ define_method(name) do |*args|
31
+ options = args.first && args.first.is_a?(Hash) && args.first
32
+ if options
33
+ options.assert_valid_keys(:force_reload, :with_deleted)
34
+ forced_reload = options[:force_reload]
35
+ with_deleted = options[:with_deleted]
36
+ else
37
+ forced_reload = false
38
+ with_deleted = false
39
+ end
40
+
41
+ if forced_reload || instance_variable_get("@#{name}").nil?
42
+
43
+ # there is probably a faster way to query this
44
+ intermediate_objects = find_associated(through, self.class, :with_deleted => with_deleted)
45
+
46
+ through_objects = intermediate_objects.map do |intermediate_object|
47
+ intermediate_object.send(name.to_s.singularize.underscore, :with_deleted => with_deleted)
48
+ end.flatten.uniq
49
+
50
+ instance_variable_set("@#{name}", through_objects)
51
+ end
52
+ instance_variable_get("@#{name}")
53
+ end
54
+ end
55
+
56
+ def define_has_many_setter_add(name)
57
+ define_method("add_#{name.to_s.singularize}") do |value|
58
+ klass = self.class.get_class_from_name(name)
59
+ raise ArgumentError, "expected #{klass} got #{value.class}" unless value.is_a?(klass)
60
+
61
+ value.send("#{self.class.foreign_key}=", id)
62
+ value.save
63
+ cached_version = instance_variable_get("@#{name}") || []
64
+ instance_variable_set("@#{name}", cached_version << value)
65
+ end
66
+ end
67
+
68
+ def define_has_many_setter_remove(name)
69
+ define_method "remove_#{name.to_s.singularize}" do |value|
70
+ klass = self.class.get_class_from_name(name)
71
+ raise ArgumentError, "expected #{klass} got #{value.class}" unless value.is_a?(klass)
72
+ raise ArgumentError, "cannot remove not mine" unless value.send(self.class.foreign_key.to_sym) == id
73
+
74
+ if self.class._find_property(name).options[:dependent] == :destroy
75
+ value.destroy
76
+ else
77
+ value.send("#{self.class.foreign_key}=", nil)
78
+ value.save
79
+ end
80
+
81
+ cached_version = instance_variable_get("@#{name}") || []
82
+ instance_variable_set("@#{name}", cached_version.delete_if{|item| item.id == value.id})
83
+ end
84
+ end
85
+
86
+ def define_has_many_setter_remove_all(name)
87
+ define_method "remove_all_#{name}" do
88
+ all = send("#{name}", :force_reload => true)
89
+
90
+ all.collect{|i| i}.each do |item|
91
+ send("remove_#{name.to_s.singularize}", item)
92
+ end
93
+ end
94
+ end
95
+
96
+ class Property
97
+ attr_reader :name, :options
98
+
99
+ def initialize(owner_clazz, name, options = {})
100
+ options = {
101
+ :dependent => :nullify,
102
+ :through => nil
103
+ }.update(options)
104
+ @name, @options = name, options
105
+
106
+ options.assert_valid_keys(:dependent, :through)
107
+
108
+ if options[:through]
109
+ owner_clazz.class_eval do
110
+ define_has_many_through_getter(name, options[:through])
111
+ end
112
+ else
113
+ owner_clazz.class_eval do
114
+ define_has_many_getter(name)
115
+ define_has_many_setter_add(name)
116
+ define_has_many_setter_remove(name)
117
+ define_has_many_setter_remove_all(name)
118
+ end
119
+ end
120
+ end
121
+
122
+ def save(object)
123
+ end
124
+
125
+ def dirty?(object)
126
+ false
127
+ end
128
+
129
+ def destroy(object)
130
+ end
131
+
132
+ def build(object, json)
133
+ end
134
+
135
+ def serialize(json, object)
136
+ end
137
+
138
+ def supports_dirty?
139
+ false
140
+ end
141
+
142
+ def association?
143
+ true
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,93 @@
1
+ module SimplyStored
2
+ module Couch
3
+ module HasOne
4
+ def has_one(name, options = {})
5
+ property name, options.merge(:class => SimplyStored::Couch::HasOne::Property)
6
+ end
7
+
8
+ def define_has_one_setter(name)
9
+ define_method("#{name}=") do |value|
10
+ klass = self.class.get_class_from_name(name)
11
+ raise ArgumentError, "expected #{klass} got #{value.class}" unless value.nil? || value.is_a?(klass)
12
+ old_value = send("#{name}", :force_reload => true)
13
+ if value.nil?
14
+ instance_variable_set("@#{name}", nil)
15
+ else
16
+ instance_variable_set("@#{name}", value)
17
+ value.send("#{self.class.foreign_key}=", id)
18
+ value.save
19
+ end
20
+
21
+ if old_value
22
+ if self.class._find_property(name).options[:dependent] == :destroy
23
+ old_value.destroy
24
+ else
25
+ old_value.send("#{self.class.foreign_property}=", nil)
26
+ old_value.save
27
+ end
28
+ end
29
+ old_value
30
+ end
31
+ end
32
+
33
+ def define_has_one_getter(name)
34
+ define_method(name) do |*args|
35
+ options = args.first && args.first.is_a?(Hash) && args.first
36
+ if options
37
+ options.assert_valid_keys(:force_reload, :with_deleted)
38
+ forced_reload = options[:force_reload]
39
+ with_deleted = options[:with_deleted]
40
+ else
41
+ forced_reload = false
42
+ with_deleted = false
43
+ end
44
+
45
+ if forced_reload || instance_variable_get("@#{name}").nil?
46
+ instance_variable_set("@#{name}", find_one_associated(name, self.class, :with_deleted => with_deleted))
47
+ end
48
+ instance_variable_get("@#{name}")
49
+ end
50
+ end
51
+
52
+ class Property
53
+ attr_reader :name, :options
54
+
55
+ def initialize(owner_clazz, name, options = {})
56
+ options = {:dependent => :nullify}.update(options)
57
+ @name, @options = name, options
58
+
59
+ options.assert_valid_keys(:dependent)
60
+
61
+ owner_clazz.class_eval do
62
+ define_has_one_getter(name)
63
+ define_has_one_setter(name)
64
+ end
65
+ end
66
+
67
+ def save(object)
68
+ end
69
+
70
+ def dirty?(object)
71
+ false
72
+ end
73
+
74
+ def destroy(object)
75
+ end
76
+
77
+ def build(object, json)
78
+ end
79
+
80
+ def serialize(json, object)
81
+ end
82
+
83
+ def supports_dirty?
84
+ false
85
+ end
86
+
87
+ def association?
88
+ true
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,74 @@
1
+ module SimplyStored
2
+ module Couch
3
+ module Validations
4
+ class ValidatesInclusionOf < ::Validatable::ValidationBase
5
+ required_option :in
6
+ option :allow_blank
7
+
8
+ def valid?(instance)
9
+ if self.allow_blank && instance.send(attribute).blank?
10
+ true
11
+ else
12
+ values = instance.send(attribute)
13
+ values = [values] unless values.is_a?(Array)
14
+ values.select{|value|
15
+ !self.in.include?(value)
16
+ }.empty?
17
+ end
18
+ end
19
+
20
+ def message(instance)
21
+ super || "must be one or more of #{self.in.join(", ")}"
22
+ end
23
+ end
24
+
25
+ class ValidatesFormatOf < ::Validatable::ValidationBase #:nodoc:
26
+ required_option :with
27
+ option :allow_blank
28
+
29
+ def valid?(instance)
30
+ (allow_blank && instance.send(attribute).blank?) ||
31
+ !(instance.send(self.attribute).to_s =~ self.with).nil?
32
+ end
33
+
34
+ def message(instance)
35
+ super || "is invalid"
36
+ end
37
+ end
38
+
39
+ class ValidatesUniquenessOf < ::Validatable::ValidationBase
40
+ def valid?(instance)
41
+ other_instance = instance.class.send("find_by_#{attribute}", instance.send(attribute))
42
+ if other_instance && other_instance != instance &&
43
+ other_instance.send(attribute) == instance.send(attribute)
44
+ false
45
+ else
46
+ true
47
+ end
48
+ end
49
+
50
+ def message(instance)
51
+ super || "#{attribute.to_s.try(:humanize) || attribute.to_s} is already taken"
52
+ end
53
+ end
54
+
55
+ def validates_inclusion_of(*args)
56
+ add_validations(args, ValidatesInclusionOf)
57
+ end
58
+
59
+ def validates_format_of(*args)
60
+ add_validations(args, ValidatesFormatOf)
61
+ end
62
+
63
+ def validates_uniqueness_of(*args)
64
+ args.each do |name|
65
+ view "by_#{name}", :key => name
66
+ end
67
+
68
+ add_validations(args, ValidatesUniquenessOf)
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+
@@ -0,0 +1,22 @@
1
+ module SimplyStored
2
+ module Couch
3
+ module Views
4
+ class ArrayPropertyViewSpec < CouchPotato::View::ModelViewSpec
5
+ def map_function
6
+ "function(doc) {
7
+ if(doc.ruby_class && doc.ruby_class == '#{@klass.name}') {
8
+ if (#{formatted_key(key)}.constructor.toString().match(/function Array()/)) {
9
+ for (var i in #{formatted_key(key)}) {
10
+ emit(#{formatted_key(key)}[i], null);
11
+ }
12
+ } else {
13
+ emit(#{formatted_key(key)}, null);
14
+ }
15
+ }
16
+ }"
17
+ end
18
+
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1 @@
1
+ require 'simply_stored/couch/views/array_property_view_spec'