Class: Blendris::Model

Inherits:
Object
  • Object
show all
Extended by:
RedisAccessor, Enumerable
Includes:
RedisAccessor
Defined in:
lib/blendris/model.rb,
lib/blendris/types.rb

Overview

Define what types are built into blendris models.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from RedisAccessor

generate_key, in_temporary_set, redis, redis

Methods included from Utils

#blank, #camelize, #constantize, #pairify, #sanitize_key

Constructor Details

#initialize(new_key, options = {}) ⇒ Model

If the :verify option isn’t set to false, then each field of this model is also verified.

Raises:

  • (ArgumentError)


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/blendris/model.rb', line 20

def initialize(new_key, options = {})
  @key = sanitize_key(new_key)
  actual_type = constantize(redis.get(key))

  raise ArgumentError.new("#{self.class.name} second argument must be a hash") unless options.kind_of? Hash
  raise TypeError.new("#{key} does not exist, not a #{self.class.name} - you may want create instead of new") if !actual_type
  raise TypeError.new("#{key} is a #{actual_type}, not a #{self.class.name}") if actual_type != self.class

  if options[:verify] != false
    parameters = self.class.local_parameters.find_all {|s| s.kind_of? Symbol}
    dne = parameters.find {|p| not self.send(p.to_s)}

    raise ArgumentError.new("#{self.class.name} #{key} is missing its #{dne}") if dne
    raise ArgumentError.new("blank keys are not allowed") if @key.length == 0
  end
end

Instance Attribute Details

#keyObject (readonly)

Returns the value of attribute key.



10
11
12
# File 'lib/blendris/model.rb', line 10

def key
  @key
end

Class Method Details

.create(*args) ⇒ Object

This method will instantiate a new object with the correct key and assign the values passed to it.



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/blendris/model.rb', line 101

def create(*args)
  parameters = local_parameters.find_all {|s| s.kind_of? Symbol}
  got = args.count
  wanted = parameters.count

  if got != wanted
    msg = "wrong number of arguments for a new #{self.class.name} (%d for %d)" % [ got, wanted ]
    raise ArgumentError.new(msg)
  end

  key = generate_key(self, args)
  current_model = redis.get(key)

  if current_model && current_model != self.name
    raise ArgumentError.new("#{key} is a #{current_model}, not a #{self.name}")
  end

  redis.set key, self.name
  redis.sadd index_key, key

  obj = new(key, :verify => false)

  parameters.each_with_index do |parm, i|
    obj[parm].set args[i]
  end

  obj
end

.eachObject



139
140
141
# File 'lib/blendris/model.rb', line 139

def each
  RedisSet.new(index_key).each {|k| yield new(k)}
end

.index_keyObject



143
144
145
# File 'lib/blendris/model.rb', line 143

def index_key
  "blendris:index:model:#{self.name}"
end

.key(*fields) ⇒ Object



130
131
132
133
134
135
136
137
# File 'lib/blendris/model.rb', line 130

def key(*fields)
  @local_parameters = fields

  @local_parameters.flatten!
  @local_parameters.compact!

  nil
end

.local_parametersObject

Parameters used when creating a new copy of this model.



178
179
180
# File 'lib/blendris/model.rb', line 178

def local_parameters
  @local_parameters ||= []
end

.on_change(*symbols, &block) ⇒ Object

Define a block to call when one of the given symbol values changes.



183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/blendris/model.rb', line 183

def on_change(*symbols, &block)
  symbols.flatten!
  symbols.compact!

  if symbols.count == 0
    on_change_table[nil] ||= []
    on_change_table[nil] << block
  else
    symbols.each do |symbol|
      on_change_table[symbol.to_s] ||= []
      on_change_table[symbol.to_s] << block
    end
  end
end

.on_change_tableObject

The hash of blocks called when fields on this object change.



199
200
201
# File 'lib/blendris/model.rb', line 199

def on_change_table
  @on_change_table ||= {}
end

.redis_symbolsObject

Variables stored in the Redis database.



173
174
175
# File 'lib/blendris/model.rb', line 173

def redis_symbols
  @redis_symbols ||= {}
end

.type(name, klass) ⇒ Object

Defines a new data type for Blendris:Model construction.



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/blendris/model.rb', line 148

def type(name, klass)
  (class << self; self; end).instance_eval do
    define_method(name) do |*args|
      varname = args.shift.to_s
      options = args.shift || {}

      options[:type] = klass
      redis_symbols[varname] = options

      # Declare the getter for this field.
      define_method(varname) do
        self[varname].get
      end

      # Declare the setter for this field, if it is not a key field.
      unless local_parameters.find {|p| p.to_s == varname}
        define_method("#{varname}=") do |value|
          self[varname].set value
        end
      end
    end
  end
end

Instance Method Details

#==(other) ⇒ Object

Compare two instances. If two instances have the same class and key, they are equal.



66
67
68
69
# File 'lib/blendris/model.rb', line 66

def ==(other)
  return false unless self.class == other.class
  return self.key == other.key
end

#[](name) ⇒ Object

Look up the given symbol by its name. The list of symbols are defined when the model is declared.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/blendris/model.rb', line 45

def [](name)
  name = name.to_s

  subkey = self.subkey(name)

  options = self.class.redis_symbols[name]

  return unless options

  on_change = lambda { self.fire_on_change_for name }
  options = options.merge(:model => self, :on_change => on_change)

  options[:type].new subkey, options
end

#destroyObject



88
89
90
91
92
# File 'lib/blendris/model.rb', line 88

def destroy
  self.class.redis_symbols.keys.each { |key| self[key].clear }
  redis.srem self.class.index_key, key
  redis.del key
end

#fieldsObject

Return a list of field names for this model.



72
73
74
# File 'lib/blendris/model.rb', line 72

def fields
  self.class.redis_symbols.map {|name, field| name.to_s}
end

#fire_on_change_for(symbol) ⇒ Object

Fire the list of blocks called when the given symbol changes.



77
78
79
80
81
82
83
84
85
86
# File 'lib/blendris/model.rb', line 77

def fire_on_change_for(symbol)
  blocks = [ self.class.on_change_table[nil], self.class.on_change_table[symbol.to_s] ]

  blocks.flatten!
  blocks.compact!

  blocks.each do |block|
    self.instance_exec symbol.to_s, &block
  end
end

#idObject

An object’s id is considered to be the SHA1 digest of its key. This is to ensure that all objects that represent the same key return the same id.



39
40
41
# File 'lib/blendris/model.rb', line 39

def id
  Digest::SHA1.hexdigest key
end

#subkey(child) ⇒ Object

Calculate the key to address the given child node.



61
62
63
# File 'lib/blendris/model.rb', line 61

def subkey(child)
  sanitize_key "#{self.key}:#{child}"
end