Class: ShyCouch::Data::CouchDocument

Inherits:
Hash
  • Object
show all
Defined in:
lib/ShyCouch/data.rb

Direct Known Subclasses

Design

Constant Summary collapse

@@constraints =

Constraints are a class variable hash keyed by subclass, with each of those keyed by “needs” and “suggests” When there’s a validation test, it cycles through each key and applies the constraints if the current class is kind_of? the object reference stored in that key. This means you can do model inheritence for common required fields. The way they’re implemented might not be performant? But models should be defined at runtime so it should be fine.

{}
@@target_db =

@@target_db is a class variable storing the default database to push a document to if push! is called without an argument it’s keyed by class name to allow different values for subclasses

{}

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ CouchDocument

Returns a new instance of CouchDocument.

Raises:

  • (TypeError)


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/ShyCouch/data.rb', line 22

def initialize(opts={})
# Assumes that the "kind" is the class name unless explicitly stated otherwise
# TODO - maybe just force it to be the class name no matter what tbh

# this is messy.
# If there's some data given, see whether it has a kind.
if opts[:data]
  if !opts[:data]["kind"]
		# If there's no kind, give the 'kind' the class name as a value
		opts[:data]["kind"] = self.class.to_s.split("::").last
  end
else 
  # if there's no data, give it data and a kind
  opts[:data] = {"kind" => self.class.to_s.split("::").last}
end

merge!(opts[:data])
@database = opts[:push_to] if opts[:push_to]
raise TypeError unless valid?
# set_up_views
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *a) ⇒ Object



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/ShyCouch/data.rb', line 256

def method_missing(m, *a)
# Makes the object behave as if the hash keys are instance properties with attr_accessors
# m.to_s =~ /=$/ ? self[$`] = a[0] : a == [] ? self[m.to_s] : super
#m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m.to_s]:super
if m.to_s =~ /=$/
  self[$`] = a[0]
else
  if a == []
		if self[m.to_s]
		  self[m.to_s]
        elsif self[m.to_sym]
          self[m.to_sym]
		else
		  super
		end
  else
		super
  end
end
end

Class Method Details

.allObject

Raises:

  • (Exception)


44
45
46
47
# File 'lib/ShyCouch/data.rb', line 44

def self.all
    # TODO
raise Exception, "not yet implemented"
end

.constraintsObject

allows instance.class.requirements to be called



8
# File 'lib/ShyCouch/data.rb', line 8

def constraints; @@constraints; end

.needs(*needs) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/ShyCouch/data.rb', line 49

def self.needs(*needs)
# this is both a setter and a getter
# initialize suggests hash for current class if not done already
# is there a better way to do this initialization?
unless @@constraints.has_key?(self)
  @@constraints[self] = {}
end
unless @@constraints[self].has_key?(:needs)
  @@constraints[self][:needs] = []
end

# Add the needs if any were passed in
if needs
  needs.each do |need|
		@@constraints[self][:needs] << need
  end
end
# Return the array
return @@constraints[self][:needs]
end

.push_to(database) ⇒ Object

Raises:

  • (TypeError)


70
71
72
73
# File 'lib/ShyCouch/data.rb', line 70

def self.push_to database
  raise TypeError, "push_to expects a ShyCouch::CouchDatabase object. Object received was a #{database.class}" unless database.kind_of? ShyCouch::CouchDatabase
  @@target_db[self] = database
end

.suggests(*suggestions) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/ShyCouch/data.rb', line 75

def self.suggests(*suggestions)
# this is both a setter and a getter
# initialize suggests hash for current class if not done already
# is there a better way to do this initialization?
@@constraints[self] = {} unless @@constraints.has_key?(self)
@@constraints[self][:suggests] = [] unless @@constraints[self].has_key?(:suggests)

# Add the suggestions if any were passed in
if !suggestions.empty?
  suggestions.each do |suggestion|
		@@constraints[self][:suggests] << suggestion
  end
end
# Return the array
return @@constraints[self][:suggests]
end

.target_dbObject



9
# File 'lib/ShyCouch/data.rb', line 9

def target_db; @@target_db[self]; end

Instance Method Details

#attr_keysObject



177
178
179
180
181
182
183
184
185
# File 'lib/ShyCouch/data.rb', line 177

def attr_keys
			# TODO - is this needed?
			# returns the keys for all the attrs that aren't the id or rev
			attr_keys = []
			self.map { |k,v|
 attr_keys << k unless k == "_id" or k == "_rev"
			}
			return attr_keys
end

#delete!(opts = {}) ⇒ Object

Raises:



239
240
241
242
243
244
245
246
# File 'lib/ShyCouch/data.rb', line 239

def delete!(opts = {})
	opts[:from] ? db = opts[:from] : db = @database
	raise ShyCouchError, "No database specified for delete" unless db
	res = db.delete_document!(self, opts)
	self["_id"] = res["id"] unless self["_id"]
	self["_rev"] = res["rev"]
	return res
end

#missing_needsObject



128
129
130
131
132
133
134
135
136
137
138
# File 'lib/ShyCouch/data.rb', line 128

def missing_needs
missing = []
@@constraints.each do |classKey, constraints|
  if self.kind_of?(classKey)
		constraints[:needs].each do |need|
		  missing << need unless has_key?(:need)
		end
  end
end
return missing
end

#missing_suggestions(opts = {}) ⇒ Object

Raises:

  • (ArgumentError)


140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/ShyCouch/data.rb', line 140

def missing_suggestions(opts = {})
			missing = []
			raise ArgumentError if opts.has_key?(:ignore_suggestions) and opts.has_key?(:ignore_suggestion)
			opts.has_key?(:ignore_suggestions) ? ign = opts[:ignore_suggestions] : 
			opts.has_key?(:ignore_suggestion) ? ign = [opts[:ignore_suggestion]] : ign = []
			
			@@constraints.each do |classKey, constraints|
 if self.kind_of?(classKey)
constraints[:suggests].each do |suggestion|
  missing << suggestion unless has_key?(:suggests) or ign.include?(suggestion)
end
 end
			end
			return missing
end

#needsObject



175
# File 'lib/ShyCouch/data.rb', line 175

def needs; self.class.needs; end

#needs?(need) ⇒ Boolean

Returns:

  • (Boolean)


156
157
158
159
160
161
162
163
# File 'lib/ShyCouch/data.rb', line 156

def needs?(need)
			@@constraints.each do |classKey, constraints|
 if self.kind_of?(classKey)
	return true if constraints[:needs].include?(need)
 end
			end
			return false
end

#pull(opts = {}) ⇒ Object



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/ShyCouch/data.rb', line 187

def pull(opts = {})
    raise ShyCouch::DocumentValidationError, "Document has no ID - cannot pull from database" unless has_key? "_id"
    if opts[:pull_from]
      db = opts[:pull_from]
    elsif @database
      db = @database
    elsif @@target_db.has_key? self.class
      db = @@target_db[self.class]
    else
      raise ShyCouch::ShyCouchError, "No database defined for document pull operation"
    end

new_doc = db.pull_document(self)
return new_doc

end

#pull!(opts = {}) ⇒ Object



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/ShyCouch/data.rb', line 204

def pull!(opts = {})
    # TODO - just call pull and merge in the result
    raise ShyCouch::DocumentValidationError, "Document has no ID - cannot pull from database" unless has_key? "_id"
    if opts[:pull_from]
      db = opts[:pull_from]
    elsif @database
      db = @database
    elsif @@target_db.has_key? self.class
      db = @@target_db[self.class]
    else
      raise ShyCouch::ShyCouchError, "No database defined for document pull operation"
    end
new_doc = pull(:pull_from => db)
if new_doc
  self.clear
  self.merge! new_doc
end
end

#push!(opts = {}) ⇒ Object



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/ShyCouch/data.rb', line 223

def push!(opts = {})
    if opts[:push_to]
      db = opts[:push_to]
    elsif @database
      db = @database
    elsif @@target_db.has_key? self.class
      db = @@target_db[self.class]
    else
      raise ShyCouch::ShyCouchError, "No database defined for document push operation"
    end
res = db.push_document!(self, opts)
self["_id"] = res["id"] unless self["_id"]
self["_rev"] = res["rev"]
return res
end

#respond_to?(method) ⇒ Boolean

Returns:

  • (Boolean)


277
278
279
280
# File 'lib/ShyCouch/data.rb', line 277

def respond_to?(method)
# so that testing for whether it responds to a method is equivalent to testing for the existence of a key
self.key?(method.to_s) ? true : super
end

#satisfies_needs?Boolean

Returns:

  • (Boolean)


92
93
94
95
96
97
98
99
100
101
102
# File 'lib/ShyCouch/data.rb', line 92

def satisfies_needs?
# Check everything in constraints that is this class or a superclass of this class
			self.class.constraints.each do |classKey, constraints|
 if self.kind_of?(classKey) and constraints[:needs]
	constraints[:needs].each do |need|
	  return false unless has_key? need.to_sym or has_key? need.to_s
	end
 end
			end
			return true
end

#satisfies_suggestions?(opts = {}) ⇒ Boolean

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/ShyCouch/data.rb', line 104

def satisfies_suggestions?(opts = {})
# Same as satisfies_needs? but can be passed options for suggestions being ignored.
raise ArgumentError if opts.has_key?(:ignore_suggestions) and opts.has_key?(:ignore_suggestion)
opts.has_key?(:ignore_suggestions) ? ign = opts[:ignore_suggestions] : 
opts.has_key?(:ignore_suggestion) ? ign = [opts[:ignore_suggestion]] : ign = []

@@constraints.each do |classKey, constraints|
  if self.kind_of?(classKey) and constraints[:suggests]
		constraints[:suggests].each do |suggestion|
		  return false unless has_key?(suggestion) or ign.include?(suggestion)
		end
  end
end
return true
end

#suggestsObject



174
# File 'lib/ShyCouch/data.rb', line 174

def suggests; self.class.suggests; end

#suggests?(suggestion) ⇒ Boolean

Returns:

  • (Boolean)


165
166
167
168
169
170
171
172
# File 'lib/ShyCouch/data.rb', line 165

def suggests?(suggestion)
			@@constraints.each do |classKey, constraints|
 if self.kind_of?(classKey)
return true if constraints[:suggests].include?(suggestion)
 end
			end
			return false
end

#to_hashObject



120
121
122
123
124
125
126
# File 'lib/ShyCouch/data.rb', line 120

def to_hash
		h = {}
		self.each do |k,v|
h[k] = v
		end
		return h
end

#to_jsonObject



250
251
252
253
254
# File 'lib/ShyCouch/data.rb', line 250

def to_json
JSON::generate(self)
rescue JSON::GeneratorError
false
end

#valid?Boolean

Returns:

  • (Boolean)


248
# File 'lib/ShyCouch/data.rb', line 248

def valid?; to_json ? true : false; end