I'm creating a class.
I wonder if there's a better way.
require 'dbi'
class Person
attr_accessor :person_id,
:last_name,
:first_name,
:home_phone,
:work_phone,
:address,
:city,
:state,
:zip
def initialize(row=nil)
if row.class == DBI::Row then
@person_id = row.by_field("person_id")
@last_name = row.by_field("last_name")
@first_name = row.by_field("first_name")
@home_phone = row.by_field("home_phone")
@work_phone = row.by_field("work_phone")
@address = row.by_field("address")
@city = row.by_field("city")
@state = row.by_field("state")
@zip = row.by_field("zip")
end
end
end
The code in initialize method is very boring.
How could I make it simpler?
Thanks in advance.
Sam
You could use Active Record.
class Person < ActiveRecord::Base
end
>> some_person = Person.new
>> some_person.last_name = 'Kong'
>> some_person.save
etc
Though ActiveRecord is known for being a component of Rails, it can be used
entirely discreetly from Rails.
e.g.
require 'active_record'
ActiveRecord::Base.establish_connection(:adapter => 'sqlite', :database => ':memory:')
class Person < Active::Record::Base
end
All set.
marcel
--
Marcel Molina Jr. <mar...@vernix.org>
At Wed, 2 Nov 2005 11:17:08 +0900,
Sam Kong wrote in [ruby-talk:163688]:
> require 'dbi'
>
Person = Struct.new(:person_id, :last_name, :first_name,
:home_phone, :work_phone,
:address, :city, :state, :zip)
class Person
def self.load_fields(row)
members.collect {|n| row.by_field(n)}
end
# may be preferable.
def self.load(row)
new(*load_fields(row))
end
def initialize(*args)
if args.size == 1 and DBI::Row === (row = args[0])
args = self.class.load_fields(row)
end
super(*args)
end
end
I'm uncertain if DBI may have more convenient method.
--
Nobu Nakada
class Person
FIELDS = :person_id, :last_name, :first_name, :home_phone,
:work_phone, :address, :city, :state, :zip
attr_accessor *FIELDS
def initialize(row=nil)
FIELDS.each { |f| instance_variable_set("@#{f}",
row.by_field(f.to_s)) } if row == DBI::Row
end
end
(though I'd advise against using the row == DBI::ROW - use
row.respond_to?(:by_field) instead, otherwise you'll probably have fun
when it comes time to unit tests...).
or if you want to make it a general case:
class DatabaseObject
def self.db_field(*args)
attr_accessor(*args)
(@__db_fields||[]).concat(args)
end
def self.db_fields
(@__db_fields||[]) + superclass.db_fields if
superclass.respond_to?(:db_fields)
end
def initialize(row=nil)
self.class.db_fields.each { |f| instance_variable_set("@#{f}",
row.by_field(f.to_s)) } if row.respond_to?(:by_field)
end
end
class Person < DatabaseObject
db_field :person_id, :last_name, :first_name, :home_phone,
:work_phone, :address, :city, :state, :zip
end
Which is pretty much what you'll get from any of the ORM libraries,
though they'll usually get the list of fields by querying the database,
so you don't even have to do that in your code.
(all code is untested - that's your job).
> -----Original Message-----
> From: Sam Kong [mailto:sam.s...@gmail.com]
> Sent: Wednesday, 2 November 2005 1:17 PM
> To: ruby-talk ML
> Subject: How can I avoid this boring code?
>
> Hi!
>
> I'm creating a class.
> I wonder if there's a better way.
>
> require 'dbi'
>
> class Person
> attr_accessor :person_id,
> :last_name,
> :first_name,
> :home_phone,
> :work_phone,
> :address,
> :city,
> :state,
> :zip
>
> def initialize(row=nil)
> if row.class == DBI::Row then
> @person_id = row.by_field("person_id")
> @last_name = row.by_field("last_name")
> @first_name = row.by_field("first_name")
> @home_phone = row.by_field("home_phone")
> @work_phone = row.by_field("work_phone")
> @address = row.by_field("address")
> @city = row.by_field("city")
> @state = row.by_field("state")
> @zip = row.by_field("zip")
> end
> end
> end
>
> The code in initialize method is very boring.
> How could I make it simpler?
>
> Thanks in advance.
>
> Sam
>
>
>
>
#####################################################################################
This email has been scanned by MailMarshal, an email content filter.
#####################################################################################
class Person
FIELDS = %w(
person_id last_name first_name home_phone work_phone address city state zip
)
def initialize r = nil
FIELDS.each{|f| send "#{ f }=", r.by_field(f)} if row.class == DBI::Row
end
end
if the Person class can dynamically set FIELDS by inspecting a table - so much
the better.
hth.
-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| anything that contradicts experience and logic should be abandoned.
| -- h.h. the 14th dalai lama
===============================================================================
I think I'd do the initialize method like this:
def initialize(row=nil)
if row.is_A? DBI::Row
row.each_with_name do |value,name|
send name.to_s+"=", value
end
end
end
And I'd make Person a Struct to get getters/setters for free.
class Hash
def to_h
self
end
end
You can define an attr method
module AttrDBI
def attr_dbi( *args )
@dbi_fields |= args
attr_accessor( *args )
end
def dbi_fields
@dbi_fields
end
end
class Person
extend AttrDBI
attr_dbi :person_id,
:last_name
...
def initialize(row)
row = row.to_h
self.class.dbi_fields.each {|f| send("#{f}=", row[f] }
end
T.