Module: Stone::Resource

Defined in:
lib/stone/resource.rb

Overview

Adds the ability to persist any class it is included in

Example

class Post

include Stone::Resource

field :body, String

end

Constant Summary collapse

@@fields =

self

{}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/stone/resource.rb', line 15

def included(base)
  rsrc_sym = base.to_s.make_key
  
  @@callbacks ||= Callbacks.new
  @@callbacks.register_klass(base)
  
  @@store ||= DataStore.new
  
  base.send(:extend, self)
  base.send(:include, ::Validatable)

  unless base.to_s.downcase =~ /spec::example::examplegroup::subclass_\d/
    # allow object to be created with a hash of attributes...
    # [] allows for obj[attribute] retrieval
    # to_s allows for stupid Rails to work
    base.class_eval <<-EOS, __FILE__, __LINE__
      def initialize(hash = nil)
        self.id = self.next_id_for_klass(self.class)
        unless hash.blank?
          hash.each_key do |k|
            if hash[k].is_a? Hash
              hash[k].each do |k,v|
                self.send(k.to_s+"=",v)
              end
            else
              self.send(k.to_s+"=", hash[k])
            end
          end
        end
      end
      
      def to_s
        id
      end
      
      def [](sym)
        self.send(sym)
      end
    EOS
  end
  
  unless @@store.resources.include?(rsrc_sym)
    @@store.resources[rsrc_sym] = DataStore.load_data(rsrc_sym)
  end
end

Instance Method Details

#[](id) ⇒ Object

Synonymous for get

Parameters

id

id of the object to retrieve



223
224
225
226
227
# File 'lib/stone/resource.rb', line 223

def [](id)
  raise "Expected Fixnum, got #{id.class} for #{self.to_s}[]" \
    unless id.class == Fixnum || id.to_i
  get(id)
end

#after_create(meth) ⇒ Object

See before_save



130
131
132
# File 'lib/stone/resource.rb', line 130

def after_create(meth)
  @@callbacks.register(:after_create, meth, self)
end

#after_delete(meth) ⇒ Object

See before_save



140
141
142
# File 'lib/stone/resource.rb', line 140

def after_delete(meth)
  @@callbacks.register(:after_delete, meth, self)
end

#after_save(meth) ⇒ Object

See before_save



119
120
121
# File 'lib/stone/resource.rb', line 119

def after_save(meth)
  @@callbacks.register(:after_save, meth, self)
end

#all(conditions = nil) ⇒ Object

Returns all objects matching conditions, or all objects if no conditions are specified

Parameters

conditions

A hash representing one or more Ruby expressions



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/stone/resource.rb', line 194

def all(conditions = nil)
  objs = []
  if conditions && conditions[:order]
    order = conditions[:order].to_a.flatten
    conditions.delete(:order)
    conditions = nil if conditions.empty?
  end
  unless conditions
    @@store.resources[self.to_s.make_key].each do |o|
      objs << o[1]
    end
  else
    objs = find(conditions, self.to_s.make_key)
  end
  if order
    raise "Order should be passed with :asc or :desc, got #{order[1].inspect}" \
      unless [:asc,:desc].include? order[1]
    begin
      objs.sort! {|x,y| x.send(order[0]) <=> y.send(order[0])}
    rescue
    end
    objs.reverse! if order[1] == :desc
  end
  objs
end

#already_exists?Boolean

Finds out if the object is already in the current DataStore instance

Returns:

  • (Boolean)


318
319
320
# File 'lib/stone/resource.rb', line 318

def already_exists?
  DataStore.determine_save_method(self, @@store) == :put
end

#before_create(meth) ⇒ Object

See before_save



125
126
127
# File 'lib/stone/resource.rb', line 125

def before_create(meth)
  @@callbacks.register(:before_create, meth, self)
end

#before_delete(meth) ⇒ Object

See before_save



135
136
137
# File 'lib/stone/resource.rb', line 135

def before_delete(meth) 
  @@callbacks.register(:before_delete, meth, self)
end

#before_save(meth) ⇒ Object

Registers the given method with the current instance of Callbacks. Upon activation (in this case, right before Resource.save is executed), the meth given is called against the object being, in this case, saved.

Parameters

meth

The method to be registered



114
115
116
# File 'lib/stone/resource.rb', line 114

def before_save(meth)
  @@callbacks.register(:before_save, meth, self)
end

#belongs_to(resource, *args) ⇒ Object

Registers a belongs_to relationship for resource

Parameters

resource

The resource to which this class belongs



163
164
165
166
167
168
169
170
# File 'lib/stone/resource.rb', line 163

def belongs_to(resource, *args)
  field "#{resource.to_s}_id".to_sym, Fixnum
  self.class_eval <<-EOS, __FILE__, __LINE__
    def #{resource.to_s} 
      #{resource.to_s.titlecase}[self.#{resource.to_s}_id]
    end
  EOS
end

#delete(id) ⇒ Object

Deletes the object with id from the current DataStore instance and its corresponding yaml file



235
236
237
238
239
240
241
242
243
# File 'lib/stone/resource.rb', line 235

def delete(id)
  fire(:before_delete)
  DataStore.delete(id, self.to_s.downcase.pluralize)
  @@store.resources[self.to_s.make_key].each_with_index do |o,i|
    @@store.resources[self.to_s.make_key].delete_at(i) if o[0] == id
  end
  fire(:after_delete)
  true
end

#field(name, klass, arg = nil) ⇒ Object

Adds a given field to @@fields and inserts an accessor for that field into klass

Parameters

name<String>


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/stone/resource.rb', line 69

def field(name, klass, arg = nil)
  
  if arg && arg[:unique] == true
    unique = true
  else
    unique = false
  end
  
  klass_sym = self.to_s.make_key
  unless @@fields[klass_sym]
    @@fields[klass_sym] = [{:name => name, 
                            :klass => klass, 
                            :unique => unique}]
  else
    @@fields[klass_sym] << {:name => name, 
                            :klass => klass, 
                            :unique => unique}
  end
  
  name = name.to_s
  
  self.class_eval <<-EOS, __FILE__, __LINE__
    def #{name}
      @#{name}
    end
    
    def #{name}=(value)
      @#{name} = value
    end
  EOS
end

#fieldsObject



229
230
231
# File 'lib/stone/resource.rb', line 229

def fields
  @@fields
end

#fields_are_valid?Boolean

Determines whether the field classes of a given object match the field class declarations

Returns:

  • (Boolean)


299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/stone/resource.rb', line 299

def fields_are_valid?
  klass_sym = self.class.to_s.make_key
  @@fields[klass_sym].each do |field|
    unless self.send(field[:name]).class == field[:klass] || self.send(field[:name]) == nil || self.already_exists?
      return false 
    end
    if field[:unique] == true
      return false if self.class.first(field[:name] => self.send(field[:name])) && !self.already_exists?
    end
  end
  true
end

#first(conditions = nil) ⇒ Object

Returns the first object matching conditions, or the first object if no conditions are specified

Parameters

conditions

A hash representing one or more Ruby expressions



181
182
183
184
185
186
187
# File 'lib/stone/resource.rb', line 181

def first(conditions = nil)
  unless conditions
    return @@store.resources[self.to_s.make_key].first[1]
  else
    return find(conditions, self.to_s.make_key)[0]
  end
end

#get(id) ⇒ Object

Allow for retrieval of an object in the current DataStore instance by id

Parameters

id

id of the object to retrieve



248
249
250
251
252
253
254
255
256
# File 'lib/stone/resource.rb', line 248

def get(id)
  id = id.to_i
  raise "Expected Fixnum, got #{id.class} for #{self.to_s}.get" \
    unless id.class == Fixnum
  @@store.resources[self.to_s.make_key].each do |o|
    return o[1] if o[0] == id
  end
  nil
end

#has_and_belongs_to_many(resource, *args) ⇒ Object

TODO: implement this



173
174
# File 'lib/stone/resource.rb', line 173

def has_and_belongs_to_many(resource, *args)
end

#has_many(resource, *args) ⇒ Object

Registers a has_many relationship for resource

Parameters

resource

the resource of which this class has many



148
149
150
151
152
153
154
# File 'lib/stone/resource.rb', line 148

def has_many(resource, *args)
  self.class_eval <<-EOS, __FILE__, __LINE__
    def #{resource.to_s} 
      #{resource.to_s.singularize.titlecase}.all("#{self.to_s.downcase}_id".to_sym.equals => self.id)
    end
  EOS
end

#has_one(resource, *args) ⇒ Object



156
157
158
# File 'lib/stone/resource.rb', line 156

def has_one(resource, *args)
  field "#{resource.to_s}_id".to_sym, Fixnum
end

#idObject



105
106
107
# File 'lib/stone/resource.rb', line 105

def id
  @id
end

#id=(value) ⇒ Object



101
102
103
# File 'lib/stone/resource.rb', line 101

def id=(value)
  @id = value
end

#new_record?Boolean

Needed for Rails to work

Returns:

  • (Boolean)


313
314
315
# File 'lib/stone/resource.rb', line 313

def new_record?
  !already_exists?
end

#next_id_for_klass(klass) ⇒ Object

Determine the next id number to use based on the last stored object’s id of class klass

Parameters

klass

The class of the object to be saved



278
279
280
281
282
283
284
285
# File 'lib/stone/resource.rb', line 278

def next_id_for_klass(klass)
  sym = klass.to_s.make_key
  if @@store.resources.has_key?(sym) && !@@store.resources[sym].blank?
    return @@store.resources[sym].last[0] + 1
  else
    return 1
  end
end

#saveObject

Save an object to the current DataStore instance.



288
289
290
291
292
293
294
295
# File 'lib/stone/resource.rb', line 288

def save
  return false unless self.fields_are_valid?
  fire(:before_save)
  return false unless self.valid?
  sym = DataStore.determine_save_method(self, @@store)
  self.class.send(sym, self)
  fire(:after_save)
end

#update_attributes(hash) ⇒ Object

Puts the attribute changes in hash

Parameters

hash

the attributes to change



261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/stone/resource.rb', line 261

def update_attributes(hash)
  hash.each_key do |k|
    if hash[k].is_a? Hash
      hash[k].each do |k,v|
        self.send(k.to_s+"=",v)
      end
    else
      self.send(k.to_s+"=", hash[k])
    end
  end
  self.save
end