active_file_record 0.0.2a → 0.0.3a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/active_file_record.gemspec +1 -1
- data/lib/active_file_record/associations.rb +57 -0
- data/lib/active_file_record/associations/association.rb +101 -0
- data/lib/active_file_record/associations/association_scope.rb +29 -0
- data/lib/active_file_record/associations/belongs_to_association.rb +78 -0
- data/lib/active_file_record/associations/builder/association.rb +46 -0
- data/lib/active_file_record/associations/builder/belongs_to.rb +13 -0
- data/lib/active_file_record/associations/singular_association.rb +64 -0
- data/lib/active_file_record/attribute_assignment.rb +25 -0
- data/lib/active_file_record/attribute_methods.rb +48 -0
- data/lib/active_file_record/attribute_methods/read.rb +26 -0
- data/lib/active_file_record/attribute_methods/write.rb +27 -0
- data/lib/active_file_record/base.rb +81 -0
- data/lib/active_file_record/callbacks.rb +21 -0
- data/lib/active_file_record/criteria.rb +10 -0
- data/lib/active_file_record/file_handler.rb +66 -0
- data/lib/active_file_record/file_handler/active_file.rb +13 -0
- data/lib/active_file_record/file_handler/attribute.rb +5 -0
- data/lib/active_file_record/inheritance.rb +42 -0
- data/lib/active_file_record/integration.rb +13 -0
- data/lib/active_file_record/nodes.rb +2 -0
- data/lib/active_file_record/nodes/binary.rb +19 -0
- data/lib/active_file_record/nodes/equality.rb +11 -0
- data/lib/active_file_record/persistence.rb +53 -0
- data/lib/active_file_record/predications.rb +9 -0
- data/lib/active_file_record/reflection.rb +140 -0
- data/lib/active_file_record/relation.rb +73 -0
- data/lib/active_file_record/relation/finder_methods.rb +88 -0
- data/lib/active_file_record/relation/predicate_builder.rb +21 -0
- data/lib/active_file_record/relation/search_methods.rb +65 -0
- data/lib/active_file_record/scoping.rb +28 -0
- data/lib/active_file_record/scoping/named.rb +72 -0
- data/lib/active_file_record/validations.rb +12 -0
- data/lib/active_file_record/version.rb +1 -1
- metadata +33 -1
    
        data/active_file_record.gemspec
    CHANGED
    
    | @@ -8,7 +8,7 @@ Gem::Specification.new do |gem| | |
| 8 8 | 
             
              gem.summary       = %q{Gem summary}
         | 
| 9 9 | 
             
              gem.homepage      = ""
         | 
| 10 10 |  | 
| 11 | 
            -
              gem.files         = `git ls-files`.split( | 
| 11 | 
            +
              gem.files         = `git ls-files`.split("\n")
         | 
| 12 12 | 
             
              gem.executables   = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
         | 
| 13 13 | 
             
              gem.test_files    = gem.files.grep(%r{^(test|spec|features)/})
         | 
| 14 14 | 
             
              gem.name          = "active_file_record"
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            require 'active_support/core_ext/array/wrap'
         | 
| 2 | 
            +
            require 'active_support/core_ext/enumerable'
         | 
| 3 | 
            +
            require 'active_support/core_ext/module/delegation'
         | 
| 4 | 
            +
            require 'active_support/core_ext/object/blank'
         | 
| 5 | 
            +
            require 'active_support/core_ext/string/conversions'
         | 
| 6 | 
            +
            require 'active_support/core_ext/module/remove_method'
         | 
| 7 | 
            +
            require 'active_support/core_ext/class/attribute'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            module ActiveFileRecord
         | 
| 10 | 
            +
              module Associations
         | 
| 11 | 
            +
                extend ActiveSupport::Autoload
         | 
| 12 | 
            +
                  extend ActiveSupport::Concern
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  autoload :Association
         | 
| 15 | 
            +
                  autoload :SingularAssociation
         | 
| 16 | 
            +
                  autoload :BelongsToAssociation
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  module Builder
         | 
| 19 | 
            +
                    autoload :Association,           'active_file_record/associations/builder/association'
         | 
| 20 | 
            +
                    autoload :SingularAssociation,   'active_file_record/associations/builder/singular_association'
         | 
| 21 | 
            +
                    autoload :BelongsTo,           'active_file_record/associations/builder/belongs_to'
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  eager_autoload do
         | 
| 25 | 
            +
                    autoload :AssociationScope, 'active_file_record/associations/association_scope'
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  attr_reader :association_cache
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def association(name)
         | 
| 31 | 
            +
                    association = association_instance_get(name)
         | 
| 32 | 
            +
                    if association.nil?
         | 
| 33 | 
            +
                      reflection  = self.class.reflect_on_association(name)
         | 
| 34 | 
            +
                      association = reflection.association_class.new(self, reflection)
         | 
| 35 | 
            +
                      association_instance_set(name, association)
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    association
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  private
         | 
| 42 | 
            +
                  def association_instance_get(name)
         | 
| 43 | 
            +
                    @association_cache[name.to_sym]
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def association_instance_set(name, association)
         | 
| 47 | 
            +
                    @association_cache[name] = association
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  module ClassMethods
         | 
| 51 | 
            +
                    def belongs_to(name, options = {})
         | 
| 52 | 
            +
                        Builder::BelongsTo.build(self, name, options)
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -0,0 +1,101 @@ | |
| 1 | 
            +
            require 'active_support/core_ext/array/wrap'
         | 
| 2 | 
            +
            require 'active_support/core_ext/object/inclusion'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module ActiveFileRecord
         | 
| 5 | 
            +
              module Associations
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                class Association
         | 
| 8 | 
            +
                  attr_reader :owner, :target, :reflection
         | 
| 9 | 
            +
                  delegate :options, :to => :reflection
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def initialize(owner, reflection)
         | 
| 12 | 
            +
                    #reflection.check_validity!
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    @target = nil
         | 
| 15 | 
            +
                    @owner, @reflection = owner, reflection
         | 
| 16 | 
            +
                    @updated = false
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    reset
         | 
| 19 | 
            +
                    reset_scope
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def reset
         | 
| 23 | 
            +
                    @loaded = false
         | 
| 24 | 
            +
                    @target = nil
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  def reset_scope
         | 
| 28 | 
            +
                    @association_scope = nil
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  def reload
         | 
| 32 | 
            +
                    reset
         | 
| 33 | 
            +
                    reset_scope
         | 
| 34 | 
            +
                    load_target
         | 
| 35 | 
            +
                    self unless target.nil?
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def klass
         | 
| 39 | 
            +
                    reflection.klass
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  def scoped
         | 
| 43 | 
            +
                    target_scope.merge(association_scope)
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def target_scope
         | 
| 47 | 
            +
                    klass.scoped
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  def association_scope
         | 
| 51 | 
            +
                    if klass
         | 
| 52 | 
            +
                      @association_scope ||= AssociationScope.new(self).scope
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  def set_inverse_instance(record)
         | 
| 57 | 
            +
                    if record && invertible_for?(record)
         | 
| 58 | 
            +
                      inverse = record.association(inverse_reflection_for(record).name)
         | 
| 59 | 
            +
                      inverse.target = owner
         | 
| 60 | 
            +
                    end
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  def inverse_reflection_for(record)
         | 
| 64 | 
            +
                    reflection.inverse_of
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  def stale_target?
         | 
| 68 | 
            +
                    loaded? && @stale_state != stale_state
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  def loaded?
         | 
| 72 | 
            +
                    @loaded
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  def load_target
         | 
| 76 | 
            +
                    if find_target?
         | 
| 77 | 
            +
                      #begin
         | 
| 78 | 
            +
                      #  if IdentityMap.enabled? && association_class && association_class.respond_to?(:base_class)
         | 
| 79 | 
            +
                      #    @target = IdentityMap.get(association_class, owner[reflection.foreign_key])
         | 
| 80 | 
            +
                      #  end
         | 
| 81 | 
            +
                      #rescue NameError
         | 
| 82 | 
            +
                      #  nil
         | 
| 83 | 
            +
                      #ensure
         | 
| 84 | 
            +
                      @target ||= find_target
         | 
| 85 | 
            +
                      #end
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                    loaded! unless loaded?
         | 
| 89 | 
            +
                    target
         | 
| 90 | 
            +
                    rescue ActiveFileRecord::RecordNotFound
         | 
| 91 | 
            +
                    reset
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  def loaded!
         | 
| 95 | 
            +
                    @loaded      = true
         | 
| 96 | 
            +
                    @stale_state = stale_state
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
              end
         | 
| 101 | 
            +
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            module ActiveFileRecord
         | 
| 2 | 
            +
              module Associations
         | 
| 3 | 
            +
                class AssociationScope
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                  attr_reader :association
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  delegate :klass, :owner, :reflection, :to => :association
         | 
| 8 | 
            +
                  delegate :chain, :conditions, :to => :reflection
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def initialize(association)
         | 
| 11 | 
            +
                    @association   = association
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def scope
         | 
| 15 | 
            +
                    scope = klass.unscoped
         | 
| 16 | 
            +
                    add_constraints(scope)
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  private
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def add_constraints(scope)
         | 
| 22 | 
            +
                    key = reflection.association_primary_key
         | 
| 23 | 
            +
                    foreign_key = reflection.foreign_key
         | 
| 24 | 
            +
                    scope.where({key => {:eq => owner[foreign_key].to_i}})
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -0,0 +1,78 @@ | |
| 1 | 
            +
            module ActiveFileRecord
         | 
| 2 | 
            +
              module Associations
         | 
| 3 | 
            +
                class BelongsToAssociation < SingularAssociation
         | 
| 4 | 
            +
                  def replace(record)
         | 
| 5 | 
            +
                    raise_on_type_mismatch(record) if record
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    update_counters(record)
         | 
| 8 | 
            +
                    replace_keys(record)
         | 
| 9 | 
            +
                    set_inverse_instance(record)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    @updated = true if record
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    self.target = record
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def updated?
         | 
| 17 | 
            +
                    @updated
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  private
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    def find_target?
         | 
| 23 | 
            +
                      !loaded? && foreign_key_present? && klass
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    #def update_counters(record)
         | 
| 27 | 
            +
                    #  counter_cache_name = reflection.counter_cache_column
         | 
| 28 | 
            +
                    #
         | 
| 29 | 
            +
                    #  if counter_cache_name && owner.persisted? && different_target?(record)
         | 
| 30 | 
            +
                    #    if record
         | 
| 31 | 
            +
                    #      record.class.increment_counter(counter_cache_name, record.id)
         | 
| 32 | 
            +
                    #    end
         | 
| 33 | 
            +
                    #
         | 
| 34 | 
            +
                    #    if foreign_key_present?
         | 
| 35 | 
            +
                    #      klass.decrement_counter(counter_cache_name, target_id)
         | 
| 36 | 
            +
                    #    end
         | 
| 37 | 
            +
                    #  end
         | 
| 38 | 
            +
                    #end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    # Checks whether record is different to the current target, without loading it
         | 
| 41 | 
            +
                    def different_target?(record)
         | 
| 42 | 
            +
                      record.nil? && owner[reflection.foreign_key] ||
         | 
| 43 | 
            +
                      record && record.id != owner[reflection.foreign_key]
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    def replace_keys(record)
         | 
| 47 | 
            +
                      if record
         | 
| 48 | 
            +
                        owner[reflection.foreign_key] = record[reflection.association_primary_key(record.class)]
         | 
| 49 | 
            +
                      else
         | 
| 50 | 
            +
                        owner[reflection.foreign_key] = nil
         | 
| 51 | 
            +
                      end
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    def foreign_key_present?
         | 
| 55 | 
            +
                      owner[reflection.foreign_key]
         | 
| 56 | 
            +
                    end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    # NOTE - for now, we're only supporting inverse setting from belongs_to back onto
         | 
| 59 | 
            +
                    # has_one associations.
         | 
| 60 | 
            +
                    def invertible_for?(record)
         | 
| 61 | 
            +
                      inverse = inverse_reflection_for(record)
         | 
| 62 | 
            +
                      inverse && inverse.macro == :has_one
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    def target_id
         | 
| 66 | 
            +
                      if options[:primary_key]
         | 
| 67 | 
            +
                        owner.send(reflection.name).try(:id)
         | 
| 68 | 
            +
                      else
         | 
| 69 | 
            +
                        owner[reflection.foreign_key]
         | 
| 70 | 
            +
                      end
         | 
| 71 | 
            +
                    end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    def stale_state
         | 
| 74 | 
            +
                      owner[reflection.foreign_key].to_s
         | 
| 75 | 
            +
                    end
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
            end
         | 
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            module ActiveFileRecord::Associations::Builder
         | 
| 2 | 
            +
              class Association
         | 
| 3 | 
            +
                class_attribute :macro
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                attr_reader :model, :name, :options, :reflection
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def self.build(model, name, options)
         | 
| 8 | 
            +
                  new(model, name, options).build
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize(model, name, options)
         | 
| 12 | 
            +
                  @model, @name, @options = model, name, options
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def mixin
         | 
| 16 | 
            +
                  @model.generated_feature_methods
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def build
         | 
| 20 | 
            +
                  reflection = model.create_reflection(self.class.macro, name, options, model)
         | 
| 21 | 
            +
                  define_accessors
         | 
| 22 | 
            +
                  reflection
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                private
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  def define_accessors
         | 
| 28 | 
            +
                    define_readers
         | 
| 29 | 
            +
                    define_writers
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def define_readers
         | 
| 33 | 
            +
                    name = self.name
         | 
| 34 | 
            +
                    mixin.redefine_method(name) do |*params|
         | 
| 35 | 
            +
                      association(name).reader(*params)
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  def define_writers
         | 
| 40 | 
            +
                    name = self.name
         | 
| 41 | 
            +
                    mixin.redefine_method("#{name}=") do |value|
         | 
| 42 | 
            +
                      association(name).writer(value)
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            require 'active_support/core_ext/object/inclusion'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module ActiveFileRecord::Associations::Builder
         | 
| 4 | 
            +
              class BelongsTo < Association #< SingularAssociation #:nodoc:
         | 
| 5 | 
            +
                self.macro = :belongs_to
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def build
         | 
| 8 | 
            +
                  reflection = super
         | 
| 9 | 
            +
                  reflection
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
            end
         | 
| @@ -0,0 +1,64 @@ | |
| 1 | 
            +
            module ActiveFileRecord
         | 
| 2 | 
            +
              module Associations
         | 
| 3 | 
            +
                class SingularAssociation < Association #:nodoc:
         | 
| 4 | 
            +
                  # Implements the reader method, e.g. foo.bar for Foo.has_one :bar
         | 
| 5 | 
            +
                  def reader(force_reload = false)
         | 
| 6 | 
            +
                    if force_reload
         | 
| 7 | 
            +
                      klass.uncached { reload }
         | 
| 8 | 
            +
                    elsif !loaded? || stale_target?
         | 
| 9 | 
            +
                      reload
         | 
| 10 | 
            +
                    end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    target
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  # Implements the writer method, e.g. foo.items= for Foo.has_many :items
         | 
| 16 | 
            +
                  def writer(record)
         | 
| 17 | 
            +
                    replace(record)
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def create(attributes = {}, options = {}, &block)
         | 
| 21 | 
            +
                    create_record(attributes, options, &block)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def create!(attributes = {}, options = {}, &block)
         | 
| 25 | 
            +
                    create_record(attributes, options, true, &block)
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def build(attributes = {}, options = {})
         | 
| 29 | 
            +
                    record = build_record(attributes, options)
         | 
| 30 | 
            +
                    yield(record) if block_given?
         | 
| 31 | 
            +
                    set_new_record(record)
         | 
| 32 | 
            +
                    record
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  private
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    def create_scope
         | 
| 38 | 
            +
                      scoped.scope_for_create.stringify_keys.except(klass.primary_key)
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    def find_target
         | 
| 42 | 
            +
                      scoped.first.tap { |record| set_inverse_instance(record) }
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                    # Implemented by subclasses
         | 
| 46 | 
            +
                    def replace(record)
         | 
| 47 | 
            +
                      raise NotImplementedError, "Subclasses must implement a replace(record) method"
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                    def set_new_record(record)
         | 
| 51 | 
            +
                      replace(record)
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    def create_record(attributes, options, raise_error = false)
         | 
| 55 | 
            +
                      record = build_record(attributes, options)
         | 
| 56 | 
            +
                      yield(record) if block_given?
         | 
| 57 | 
            +
                      saved = record.save
         | 
| 58 | 
            +
                      set_new_record(record)
         | 
| 59 | 
            +
                      raise RecordInvalid.new(record) if !saved && raise_error
         | 
| 60 | 
            +
                      record
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            module ActiveFileRecord
         | 
| 2 | 
            +
              module AttributeAssignment
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                extend ActiveSupport::Concern
         | 
| 5 | 
            +
                include ActiveModel::MassAssignmentSecurity
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def attributes=(new_attributes)
         | 
| 8 | 
            +
                  return unless new_attributes.is_a?(Hash)
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  assign_attributes(new_attributes)
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def assign_attributes(new_attributes, options = {})
         | 
| 14 | 
            +
                  return if new_attributes.blank?
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  attributes = new_attributes.stringify_keys
         | 
| 17 | 
            +
                  attributes = sanitize_for_mass_assignment(attributes) unless options[:without_protection]
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  attributes.each do |k, v|
         | 
| 20 | 
            +
                    send("#{k}=", v)
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,48 @@ | |
| 1 | 
            +
            module ActiveFileRecord
         | 
| 2 | 
            +
              module AttributeMethods
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                extend ActiveSupport::Concern
         | 
| 5 | 
            +
                include ActiveModel::AttributeMethods
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                included do
         | 
| 8 | 
            +
                  include Read
         | 
| 9 | 
            +
                  include Write
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  class_attribute :_fields
         | 
| 12 | 
            +
                  self._fields = []
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def [](attr_name)
         | 
| 15 | 
            +
                    read_attribute(attr_name)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def []=(attr_name, value)
         | 
| 19 | 
            +
                    write_attribute(attr_name, value)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def attribute_names
         | 
| 24 | 
            +
                  @attributes.keys
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
             | 
| 28 | 
            +
                module ClassMethods
         | 
| 29 | 
            +
                  def fields(*names)
         | 
| 30 | 
            +
                    self._fields += names
         | 
| 31 | 
            +
                    define_attribute_methods names
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  def initialize_attributes(fields_names)
         | 
| 35 | 
            +
                    Hash[fields_names.map {|attribute| [attribute, nil]}]
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def generated_methods
         | 
| 39 | 
            +
                    @generated_methods ||= begin
         | 
| 40 | 
            +
                    mod = Module.new
         | 
| 41 | 
            +
                    include(mod)
         | 
| 42 | 
            +
                      mod
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
            end
         |