class Fixturize

Constants

INSERT_TYPES
METHODS_FOR_INSTRUMENTATION

Attributes

current_instrumentation[RW]
database[RW]
database_version[W]
enabled[RW]
relative_path_root[RW]

Public Class Methods

_instrument_database(collection_name, method_name, *args) click to toggle source
# File lib/fixturize.rb, line 147
def _instrument_database(collection_name, method_name, *args)
  collection.insert_aliased_from_fixturize({
    :type => INSTRUMENT_DATABASE,
    :name => current_instrumentation,
    :collection_name => collection_name.to_s,
    :method_name => method_name.to_s,
    :args => BSON::Binary.new(Marshal.dump(args)),
    :timestamp => Time.now.to_f, # unused, just for reference
    # :json_args => args.to_json,
  })
end
clear_cache!() click to toggle source
# File lib/fixturize.rb, line 53
def clear_cache!
  database.collections.each do |c|
    if c.name =~ /fixturize_/
      c.drop
    end
  end
end
clear_old_versions!() click to toggle source
# File lib/fixturize.rb, line 61
def clear_old_versions!
  return unless enabled?

  database.collections.select do |c|
    c.name =~ /fixturize_/ && c.name != self.collection_name
  end.each do |c|
    c.drop
  end
end
collection() click to toggle source
# File lib/fixturize.rb, line 45
def collection
  if !database
    raise "Fixturize is not yet setup!  Make sure the database is set!"
  end

  database.collection(collection_name)
end
collection_name() click to toggle source
# File lib/fixturize.rb, line 41
def collection_name
  "fixturize_#{database_version}_"
end
database_version() click to toggle source
# File lib/fixturize.rb, line 33
def database_version
  @database_version ||= 0
end
enabled?() click to toggle source
# File lib/fixturize.rb, line 29
def enabled?
  enabled ? true : false
end
fixture_name(name = nil, &block) click to toggle source
# File lib/fixturize.rb, line 91
def fixture_name(name = nil, &block)
  if !name && block.respond_to?(:source_location)
    # is this portable?
    file_name, line_number = block.source_location

    if relative_path_root && file_name.start_with?(relative_path_root)
      file_name = file_name[relative_path_root.length + 1 .. -1]
    end

    name = [file_name, line_number].join(":")

    if block.respond_to?(:source)
      name += ":" + Digest::SHA1.hexdigest(block.source.strip)
    end
  end

  if !name
    raise "A name must be given to fixturize"
  end

  name.to_s
end
fixturize(name = nil) { || ... } click to toggle source
# File lib/fixturize.rb, line 114
def fixturize(name = nil, &block)
  raise LocalJumpError.new("fixturize requires a block") unless block_given?
  return yield if !enabled?

  name = fixture_name(name, &block)
  self.current_instrumentation = name

  all_instrumentations = collection.
    find({ :name => name }).
    sort({ :_id => Mongo::ASCENDING }).
    to_a

  db_instrumentations = all_instrumentations.select { |i| i['type'] == INSTRUMENT_DATABASE }

  if db_instrumentations.any?
    uninstall!

    db_instrumentations.each do |instrumentation|
      load_data_from(instrumentation)
    end

    ivar_instrumentations = all_instrumentations.select { |i| i['type'] == INSTRUMENT_IVARS }

    if ivar_instrumentations.any?
      ivar_instrumentations.each do |instrumentation|
        load_ivars_from(instrumentation, caller_of_block(block))
      end
    end
  else
    safe_install(&block)
  end
end
index!() click to toggle source
# File lib/fixturize.rb, line 82
def index!
  return unless enabled?

  collection.ensure_index({
    :name => Mongo::ASCENDING,
    :type => Mongo::ASCENDING,
  })
end
refresh!(name = nil) click to toggle source
# File lib/fixturize.rb, line 71
def refresh!(name = nil)
  return unless enabled?

  if name
    name = fixture_name(name)
    collection.remove({ :name => name })
  else
    collection.drop()
  end
end
reset_version!() click to toggle source
# File lib/fixturize.rb, line 37
def reset_version!
  @database_version = nil
end

Private Class Methods

caller_of_block(block) click to toggle source
# File lib/fixturize.rb, line 194
def caller_of_block(block)
  block.binding.eval("self")
end
install!() { || ... } click to toggle source
# File lib/fixturize.rb, line 205
    def install!(&block)
      METHODS_FOR_INSTRUMENTATION.each do |method_name|
        Mongo::Collection.class_eval <<-HERE, __FILE__, __LINE__
          unless instance_methods.include?(:#{method_name}_aliased_from_fixturize)
            alias_method :#{method_name}_aliased_from_fixturize, :#{method_name}

            def #{method_name}(*args, &block)
              Fixturize._instrument_database(@name, :#{method_name}, *args, &block)
              #{method_name}_aliased_from_fixturize(*args, &block)
            end
          end
        HERE
      end

      block_caller = caller_of_block(block)

      begin
        ret_val = yield
      rescue => e
        collection.remove_aliased_from_fixturize({
          :name => current_instrumentation,
        })

        raise e
      end

      instrument_ivars(block_caller.instance_variables, block_caller)
      ret_val
    end
instrument_ivars(ivars, context) click to toggle source
# File lib/fixturize.rb, line 161
def instrument_ivars(ivars, context)
  ivars.each do |ivar|
    obj = context.instance_variable_get(ivar)

    # TODO: Use duck typing?
    if defined?(MongoMapper) && obj.kind_of?(MongoMapper::Document)
      collection.insert_aliased_from_fixturize({
        :type => INSTRUMENT_IVARS,
        :name => current_instrumentation,
        :ivar => ivar,
        :model => obj.class.to_s,
        :id => obj.id,
        :timestamp => Time.now.to_f, # unused, just for reference
      })
    end
  end
end
load_data_from(instrumentation) click to toggle source
# File lib/fixturize.rb, line 179
def load_data_from(instrumentation)
  collection = database.collection(instrumentation['collection_name'])
  collection.send(instrumentation['method_name'], *Marshal.load(instrumentation['args'].to_s))
end
load_ivars_from(instrumentation, target_obj) click to toggle source
# File lib/fixturize.rb, line 184
def load_ivars_from(instrumentation, target_obj)
  ivar = instrumentation['ivar']
  model_str = instrumentation['model']
  id = instrumentation['id']

  model = Object.const_get(model_str)
  obj = model.find(id)
  target_obj.instance_variable_set(ivar, obj)
end
safe_install(&block) click to toggle source
# File lib/fixturize.rb, line 198
def safe_install(&block)
  install!(&block)
ensure
  self.current_instrumentation = nil
  uninstall!
end
uninstall!() click to toggle source
# File lib/fixturize.rb, line 235
    def uninstall!
      METHODS_FOR_INSTRUMENTATION.each do |method_name|
        Mongo::Collection.class_eval <<-HERE, __FILE__, __LINE__
          if instance_methods.include?(:#{method_name}_aliased_from_fixturize)
            alias_method :#{method_name}, :#{method_name}_aliased_from_fixturize
            remove_method :#{method_name}_aliased_from_fixturize
          end
        HERE
      end
    end