Module: LionAttr::ClassMethods

Defined in:
lib/lion_attr.rb

Overview

Since:

  • 0.1.0

Instance Method Summary collapse

Instance Method Details

#_fetch_from_db(id) ⇒ Mongoid::Document

Query the object by id, and create a cache version in Redis.

Parameters:

  • id (String)

Returns:

  • (Mongoid::Document)

Since:

  • 0.1.0



124
125
126
127
128
# File 'lib/lion_attr.rb', line 124

def _fetch_from_db(id)
  object = find(id)
  @internal_redis.set(id, object.as_document.to_json)
  object
end

#_incr(key, type, internal_redis = nil, increment = 1, &block) ⇒ Object

Since:

  • 0.1.0



209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/lion_attr.rb', line 209

def _incr(key, type, internal_redis = nil, increment = 1, &block)
  internal_redis ||= InternalRedis.new(name)
  if block && !internal_redis.exists(key)
    internal_redis.setnx key, block.call
  end
  if type == Integer
    internal_redis.incrby(key, increment)
  elsif type == Float
    internal_redis.incrbyfloat(key, increment)
  else
    'ERR hash value is not a number'
  end
end

#_key(id, field) ⇒ Object

Since:

  • 0.1.0



182
183
184
# File 'lib/lion_attr.rb', line 182

def _key(id, field)
  "#{id}_#{field}"
end

#fetch(id) ⇒ Mongoid::Document

Fetch the object specified with an id from Redis. It will not touch the database (Mongdb). If that object is not available on Redis or invalid (due to model changes, it will make a query to the database (Mongodb).

Parameters:

  • id (String)

Returns:

  • (Mongoid::Document)

Since:

  • 0.1.0



108
109
110
111
112
113
114
115
116
117
118
# File 'lib/lion_attr.rb', line 108

def fetch(id)
  @internal_redis ||= InternalRedis.new(name)
  string_object = @internal_redis.get(id)
  if string_object.nil?
    object = _fetch_from_db(id)
  else
    object = new(JSON.load(string_object))
  end
rescue Mongoid::Errors::UnknownAttribute
  object = _fetch_from_db(id)
end

#generate_fetch_cache_method(name) ⇒ Object

Since:

  • 0.1.0



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/lion_attr.rb', line 240

def generate_fetch_cache_method(name)
  re_define_method("#{name}") do
    @internal_redis ||= InternalRedis.new(self.class.name)
    raw = @internal_redis.get(key(name))
    field = fields[name.to_s]
    if raw.nil?
      raw = read_attribute(name)
      if lazy_settable?(field, raw)
        value = write_attribute(name, field.eval_default(self))
      else
        value = field.demongoize(raw)
        attribute_will_change!(name) if value.resizable?
      end

      @internal_redis.set(key(name), raw)
    else
      value = field.demongoize(raw)
    end
    value
  end
end

#generate_incr_methodObject

Since:

  • 0.1.0



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

def generate_incr_method
  define_method('incr') do |field, increment = 1|
  begin
    unless self.class.live_fields.include?(field)
      fail "#{field} is not a live attributes"
    end
    @internal_redis ||= InternalRedis.new(self.class.name)
    self.class._incr(key(field),
                     fields[field.to_s].type,
                     @internal_redis,
                     increment) { read_attribute(field) }
  rescue => e
    e.message
  end
  end
end

#generate_update_db_method(_fields) ⇒ Object

Since:

  • 0.1.0



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/lion_attr.rb', line 166

def generate_update_db_method(_fields)
  define_method('update_db') do
    @live_keys ||= self.class.live_fields.map { |f| key(f) }
    @internal_redis ||= InternalRedis.new(self.class.name)
    redis_values = @internal_redis.mget(@live_keys)
    self.class.live_fields.each_with_index do |f, i|
      if read_attribute(f) != redis_values[i]
        write_attribute(f, redis_values[i])
      end
    end
    # TODO: This could be improved by using batch save instead of saving
    # individual document
    save
  end
end

#incr(id, field, increment = 1, internal_redis = nil) ⇒ Integer, ...

Increase live attributes value in Redis. If the live attributes are not Integer nor Float, a String message will be returned. Otherwise, increased value will be returned.

Parameters:

  • id (String)
  • field (String, Symbol)
  • increment (Integer) (defaults to: 1)
  • internal_redis (InternalRedis) (defaults to: nil)

Returns:

  • (Integer, Float, String)

Since:

  • 0.1.0



196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/lion_attr.rb', line 196

def incr(id, field, increment = 1, internal_redis = nil)
  unless self.live_fields.include?(field)
    fail "#{field} is not a live attributes"
  end
  internal_redis ||= InternalRedis.new(name)
  _incr(_key(id, field), fields[field.to_s].type,
        @internal_redis, increment) do
    find(id).read_attribute(field)
  end
rescue => e
  e.message
end

#live(*fields) ⇒ Object

Since:

  • 0.1.0



139
140
141
142
143
144
145
146
147
148
# File 'lib/lion_attr.rb', line 139

def live(*fields)
  fields.each do |field|
    generate_fetch_cache_method(field)
    # generate_set_cache_method(field)
  end
  generate_update_db_method(fields)
  generate_incr_method
  (@live_fields ||= []).push(*fields)
  set_callback(:destroy, :after, :clean_cache_after_destroy)
end

#live_fieldsObject

Get all live fields of the class

Examples:

article.class.live_fields
#=> [:view]

Since:

  • 0.1.0



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

def live_fields
  @live_fields
end

#live_keyObject

Get object key to interact with Redis. If you don’t specify the live_key :id will be used by default.

Since:

  • 0.1.0



162
163
164
# File 'lib/lion_attr.rb', line 162

def live_key
  @key || :id
end

#live_key=(field) ⇒ Object

Specify the field which is used to get storage key for the object.

Examples:

article.class.live_key = :url
# Whenever LionAttr need to use object key, it gets from :url

Parameters:

  • field (String, Symbole)

Since:

  • 0.1.0



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

def live_key=(field)
  @key = field
end