Posts Tagged ‘datamapper’
dm-is-remixable and overwritten property accessors
March 31st, 2009 •
tags: datamapper, ruby
I just stumbled across some weirdness in dm-is-remixable. Seems like overwritten property writers work, whereas overwritten property readers don’t … hmm …
working with UTC and datamapper
February 23rd, 2009 •
3 comments
tags: datamapper, ruby
# stick this in the before_app_loads block in init.rb
# if this maybe finds its way into dm-more, this wouldn't be necessary anymore
module DataMapper
module Types
class UtcDateTime < DataMapper::Type
primitive DateTime
def self.load(v, property)
if v.nil?
nil
elsif v.is_a?(DateTime)
::DateTime.new(v.year, v.month, v.day, v.hour, v.min, v.sec, 0)
else
raise ArgumentError.new("+value+ must be nil or a DateTime")
end
end
def self.dump(v, property)
if v.nil?
nil
elsif v.is_a?(String)
Time.parse(v).utc.to_datetime
elsif v.is_a?(DateTime)
Time.parse(v.to_s).utc.to_datetime
else
raise ArgumentError.new("+value+ must be nil or a String or a DateTime")
end
end
end # class UtcDateTime
UTCDateTime = UtcDateTime
end # module Types
end # module DataMapper
module DataMapper
module Timestamp
def set_timestamps
return unless dirty? || new_record?
TIMESTAMP_PROPERTIES.each do |name,(_type,proc)|
if model.properties.has_property?(name)
self.send("#{name}=", proc.call(self, model.properties[name]))
end
end
end
def utc_timestamped?
self.class.utc_timestamped?
end
module ClassMethods
def timestamps(*names)
raise ArgumentError, 'You need to pass at least one argument' if names.empty?
# if the last element in names is a Hash:
# extract this hash and look for a :utc key
opts = names.last.is_a?(Hash) ? names.pop : nil
utc_possible = names.include?(:created_at) || names.include?(:updated_at)
@utc = opts && opts[:utc] && utc_possible
names.each do |name|
case name
when *TIMESTAMP_PROPERTIES.keys
type = TIMESTAMP_PROPERTIES[name].first
property name, type, :nullable => false, :auto_validation => false
if type == DateTime && @utc # UTC makes no sense for Date
define_method "#{name}=", UTC::PROPERTY_WRITER.call(name, type)
define_method "#{name}", UTC::PROPERTY_READER.call(name, type)
end
when :at
timestamps(:created_at, :updated_at, :utc => @utc)
when :on
timestamps(:created_on, :updated_on) # UTC makes no sense for Date
else
raise InvalidTimestampName, "Invalid timestamp property name '#{name}'"
end
end
end
def utc_timestamped?
!!@utc
end
end
module UTC
PROPERTY_WRITER = lambda { |name, type|
typecast = "to_#{type.name.downcase}"
lambda { |dt| attribute_set(name, Time.parse(dt.to_s).utc.send(typecast)) }
}
PROPERTY_READER = lambda { |name, type|
lambda {
return nil unless dt = attribute_get(name)
if type == Date
Date.new(dt.year, dt.month, dt.day, 0)
elsif type == DateTime
DateTime.new(dt.year, dt.month, dt.day, dt.hour, dt.min, dt.sec, 0)
else
nil
end
}
}
end
end
end
sharing common properties between datamapper models
January 17th, 2009 •
tags: datamapper, ruby
require "rubygems"
require "dm-core"
module Locatable
# using a lambda instead of self.included(base) class_eval hack
# to add properties and/or associations that are shared by many models
#
# use this module in two steps.
#
# 1) eval the lambda with property definitions in class scope
# class_eval &Locatable::PROPERTIES
#
# 2) include the common instance methods if any
# include Locatable
#
# this also makes it possible, that this module gets included at a different
# time (place in code) than the property definitions, which might come in
# handy in situations where you deal with overriding methods with/from
# this module (say you want to establish aliases for methods that only get
# added by some calls to belongs_to or has or the likes)
PROPERTIES = lambda do
property :location_id, Integer, :nullable => false
end
ASSOCIATIONS = lambda do
belongs_to :location
end
# common instance methods
# need to support different protocol
# for whatever reason ...
alias :information :description
def latitude
location.latitude
end
def longitude
location.longitude
end
# ...
end
class Item
include DataMapper::Resource
# properties
property :id, Serial
property :owner_id, Integer, :nullable => false
# using the lambda here makes it very explicit what's going on.
# it also allows to preserve the property order in the underlying
# table definition in a natural and consistent way.
class_eval &Locatable::PROPERTIES
property :name, String
property :description, Text
# associations
# again, using the lambda here makes it very explicit what's going on.
class_eval &Locatable::ASSOCIATIONS
belongs_to :owner
has n, :item_categories
has n, :categories, :through => :item_categories
# include Locatable methods after #description exists
# we want to support the alias
include Locatable
end
default ordering with datamapper
December 10th, 2008 •
tags: datamapper, ruby
Thanks to Adam French for this tip on the datamapper mailinglist.
You’d essentially be update’ing the default query object that all
calls to all() and first() start off with before applying the user’s
parameters
class Post include DataMapper::Resource #... other properties here default_scope(:default).update(:order => [:created_at.desc]) end
datamapper stand alone script (for bugreports)
December 10th, 2008 •
tags: datamapper, ruby
#!/usr/bin/env ruby require 'rubygems' gem 'dm-core', '~>0.9.8' require 'dm-core' DataMapper::Logger.new(STDOUT, :debug) # DataObjects::Sqlite3.logger = DataObjects::Logger.new(STDOUT, :debug) DataMapper.setup(:default, 'sqlite3::memory:') # here come the demo class(es) DataMapper.auto_migrate! # here comes initial creation of records if necessary puts '-' * 80 # here comes the demo code demonstrating the error or whatever
relevant merb / datamapper ticket information
December 2nd, 2008 •
2 comments
tags: datamapper, merb
When filing a ticket for merb or datamapper, it’s a good idea to put the following information into the ticket
(Suggested by Dan Kubb - dkubb in #datamapper)
uname -a (for unixes at least) ruby --version mysql --version (or the equivalent for your db) gem list '\A(?:(?:d[mo]|merb)[_-]|data_?(?:mapper|objects)|extlib)'
merb_resource_controller now supports nested (singleton) resources
November 27th, 2008 •
tags: datamapper, merb, ruby
merb_resource_controller is a merb plugin that provides the default CRUD actions for controllers and allows for easy customization of the generated actions. You might have already heard of or used one of its counterparts in rails world, like make_resourceful, James Golick’s resource_controller, Ian White’s resources_controller or other projects on github. Thx a lot for the inspiration guys!
As it so happens, today merb_resource_controller learned to work with arbitrarily nested (singleton) resources AND got a massive README update :-)
So if you are a merbivore you should really check it out and give me feedback!
What’s left to say? I say let the code do the talking …
class Articles < Application controlling :articles end
How to uninstall datamapper (or any rubygem)
November 19th, 2008 •
3 comments
tags: datamapper, ruby
gem list dm --no-version | xargs sudo gem uninstall -a -x
gem list data --no-version | xargs sudo gem uninstall -a -x
gem list do_ --no-version | xargs sudo gem uninstall -a -x
fun with merb -i and dm-sweatshop
November 14th, 2008 •
tags: datamapper, dm-sweatshop, merb
# in spec/fixtures.rb
# of course these are just examples of what the content could look like
User.fix {{
:login => /\w+/.gen,
:password => (password = /\w{12}/.gen),
:password_confirmation => password
}}
GeoPoint.fix {{
:lat => BigDecimal.new((rand * 180 - 90).to_s),
:lng => BigDecimal.new((rand * 360 - 180).to_s),
}}
Location.fix {{
:geo_point => unique { GeoPoint.gen },
:name => /\w+/.gen,
:short_description => /\w+/.gen,
:long_description => /\w+/.gen,
:address => /\w+/.gen
}}
20.times { Location.gen }
# in config/init.rb
Merb::BootLoader.after_app_loads do
# This will get executed after your app's classes have been loaded.
if Merb.env == "development"
# allows for easy playin around in merb -i
# dm-sweatshop will provide enough data for that
require Merb.root / "spec" / "spec_fixtures"
end
end
support for speccing datamapper models with rspec
October 10th, 2008 •
tags: datamapper, rspec, ruby
# Put this in spec_helper.rb
module SpecSupport
def self.unload_class(*classes)
classes.each do |c|
Object.send(:remove_const, c) if Object.const_defined?(c)
end
end
def self.fresh_class(name, superclass = nil, &block)
unload_class(name)
args = superclass ? [ superclass ] : []
Object.const_set(name, Class.new(*args))
Object.const_get(name).class_eval(&block)
end
def self.fresh_model(name)
fresh_class(name) do
include DataMapper::Resource
property :id, DataMapper::Types::Serial
property :created_at, DateTime
property :updated_at, DateTime
end
end
end