Class: FrozenRecord::Base

Inherits:
Object
  • Object
show all
Extended by:
ActiveModel::Naming, ActiveSupport::DescendantsTracker
Includes:
ActiveModel::AttributeMethods, ActiveModel::Conversion, ActiveModel::Serializers::JSON, ActiveModel::Serializers::Xml
Defined in:
lib/frozen_record/base.rb,
lib/frozen_record/serialization.rb

Defined Under Namespace

Classes: ThreadSafeStorage

Constant Summary collapse

FIND_BY_PATTERN =
/\Afind_by_(\w+)(!?)/
FALSY_VALUES =
[false, nil, 0, -''].to_set

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attrs = {}) ⇒ Base

Returns a new instance of Base.



286
287
288
# File 'lib/frozen_record/base.rb', line 286

def initialize(attrs = {})
  @attributes = attrs.freeze
end

Class Attribute Details

.abstract_classObject

Returns the value of attribute abstract_class.



90
91
92
# File 'lib/frozen_record/base.rb', line 90

def abstract_class
  @abstract_class
end

Class Method Details

.abstract_class?Boolean

Returns:

  • (Boolean)


99
100
101
# File 'lib/frozen_record/base.rb', line 99

def abstract_class?
  defined?(@abstract_class) && @abstract_class
end

.add_index(attribute, unique: false) ⇒ Object



154
155
156
157
# File 'lib/frozen_record/base.rb', line 154

def add_index(attribute, unique: false)
  index = unique ? UniqueIndex.new(self, attribute) : Index.new(self, attribute)
  self.index_definitions = index_definitions.merge(index.attribute => index).freeze
end

.attribute(attribute, klass) ⇒ Object



159
160
161
# File 'lib/frozen_record/base.rb', line 159

def attribute(attribute, klass)
  self.attribute_deserializers = attribute_deserializers.merge(attribute.to_s => klass).freeze
end

.attributesObject



92
93
94
95
96
97
# File 'lib/frozen_record/base.rb', line 92

def attributes
  @attributes ||= begin
    load_records
    @attributes
  end
end

.base_path=(base_path) ⇒ Object



85
86
87
88
# File 'lib/frozen_record/base.rb', line 85

def base_path=(base_path)
 @file_path = nil
 set_base_path(base_path)
end

.current_scopeObject Also known as: all



103
104
105
# File 'lib/frozen_record/base.rb', line 103

def current_scope
  store[:scope] ||= Scope.new(self)
end

.current_scope=(scope) ⇒ Object



108
109
110
# File 'lib/frozen_record/base.rb', line 108

def current_scope=(scope)
  store[:scope] = scope
end

.default_attributes=(default_attributes) ⇒ Object



73
74
75
# File 'lib/frozen_record/base.rb', line 73

def default_attributes=(default_attributes)
  set_default_attributes(default_attributes.transform_keys(&:to_s))
end

.eager_load!Object



185
186
187
188
189
# File 'lib/frozen_record/base.rb', line 185

def eager_load!
  return if auto_reloading || abstract_class?

  load_records
end

.file_pathObject

Raises:

  • (ArgumentError)


116
117
118
119
120
121
122
123
124
125
126
# File 'lib/frozen_record/base.rb', line 116

def file_path
  raise ArgumentError, "You must define `#{name}.base_path`" unless base_path
  @file_path ||= begin
    file_path = File.join(base_path, backend.filename(name))
    if !File.exist?(file_path) && File.exist?("#{file_path}.erb")
      "#{file_path}.erb"
    else
      file_path
    end
  end
end

.find(id) ⇒ Object

Raises:



132
133
134
135
# File 'lib/frozen_record/base.rb', line 132

def find(id)
  raise RecordNotFound, "Can't lookup record without ID" unless id
  find_by(primary_key => id) or raise RecordNotFound, "Couldn't find a record with ID = #{id.inspect}"
end

.find_by(criterias) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/frozen_record/base.rb', line 137

def find_by(criterias)
  if criterias.size == 1
    criterias.each do |attribute, value|
      attribute = attribute.to_s
      if index = index_definitions[attribute]
        load_records
        return index.lookup(value).first
      end
    end
  end
  current_scope.find_by(criterias)
end

.find_by!(criterias) ⇒ Object



150
151
152
# File 'lib/frozen_record/base.rb', line 150

def find_by!(criterias)
  find_by(criterias) or raise RecordNotFound, "No record matched"
end

.find_by_id(id) ⇒ Object



128
129
130
# File 'lib/frozen_record/base.rb', line 128

def find_by_id(id)
  find_by(primary_key => id)
end

.loadObject



219
# File 'lib/frozen_record/base.rb', line 219

alias_method :load, :new

.load_records(force: false) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/frozen_record/base.rb', line 197

def load_records(force: false)
  if force || (auto_reloading && file_changed?)
    unload!
  end

  @records ||= begin
    records = backend.load(file_path)
    if attribute_deserializers.any? || default_attributes
      records = records.map { |r| assign_defaults!(deserialize_attributes!(r.dup)).freeze }.freeze
    end
    @attributes = list_attributes(records).freeze
    define_attribute_methods(@attributes.to_a)
    records = FrozenRecord.ignore_max_records_scan { records.map { |r| load(r) }.freeze }
    index_definitions.values.each { |index| index.build(records) }
    records
  end
end

.memsize(object = self, seen = Set.new.compare_by_identity) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/frozen_record/base.rb', line 163

def memsize(object = self, seen = Set.new.compare_by_identity)
  return 0 unless seen.add?(object)

  size = ObjectSpace.memsize_of(object)
  object.instance_variables.each { |v| size += memsize(object.instance_variable_get(v), seen) }

  case object
  when Hash
    object.each { |k, v| size += memsize(k, seen) + memsize(v, seen) }
  when Array
    object.each { |i| size += memsize(i, seen) }
  end
  size
end

.new(attrs = {}) ⇒ Object



222
223
224
# File 'lib/frozen_record/base.rb', line 222

def new(attrs = {})
  load(assign_defaults!(deserialize_attributes!(attrs.transform_keys(&:to_s))))
end

.primary_key=(primary_key) ⇒ Object



79
80
81
# File 'lib/frozen_record/base.rb', line 79

def primary_key=(primary_key)
  set_primary_key(-primary_key.to_s)
end

.respond_to_missing?(name) ⇒ Boolean

Returns:

  • (Boolean)


178
179
180
181
182
183
# File 'lib/frozen_record/base.rb', line 178

def respond_to_missing?(name, *)
  if name.to_s =~ FIND_BY_PATTERN
    load_records # ensure attribute methods are defined
    return true if $1.split('_and_').all? { |attr| instance_method_already_implemented?(attr) }
  end
end

.scope(name, body) ⇒ Object



215
216
217
# File 'lib/frozen_record/base.rb', line 215

def scope(name, body)
  singleton_class.send(:define_method, name, &body)
end

.set_base_pathObject



83
# File 'lib/frozen_record/base.rb', line 83

alias_method :set_base_path, :base_path=

.set_default_attributesObject



71
# File 'lib/frozen_record/base.rb', line 71

alias_method :set_default_attributes, :default_attributes=

.set_primary_keyObject



77
# File 'lib/frozen_record/base.rb', line 77

alias_method :set_primary_key, :primary_key=

.unload!Object



191
192
193
194
195
# File 'lib/frozen_record/base.rb', line 191

def unload!
  @records = nil
  index_definitions.values.each(&:reset)
  undefine_attribute_methods
end

.with_max_records_scan(value) ⇒ Object



63
64
65
66
67
68
69
# File 'lib/frozen_record/base.rb', line 63

def with_max_records_scan(value)
  previous_max_records_scan = max_records_scan
  self.max_records_scan = value
  yield
ensure
  self.max_records_scan = previous_max_records_scan
end

Instance Method Details

#==(other) ⇒ Object



303
304
305
# File 'lib/frozen_record/base.rb', line 303

def ==(other)
  super || other.is_a?(self.class) && !id.nil? && other.id == id
end

#[](attr) ⇒ Object Also known as: attribute



298
299
300
# File 'lib/frozen_record/base.rb', line 298

def [](attr)
  @attributes[attr.to_s]
end

#attributesObject



290
291
292
# File 'lib/frozen_record/base.rb', line 290

def attributes
  @attributes.dup
end

#idObject



294
295
296
# File 'lib/frozen_record/base.rb', line 294

def id
  self[self.class.primary_key]
end

#persisted?Boolean

Returns:

  • (Boolean)


307
308
309
# File 'lib/frozen_record/base.rb', line 307

def persisted?
  true
end

#to_keyObject



311
312
313
# File 'lib/frozen_record/base.rb', line 311

def to_key
  [id]
end