Class: VORuby::ActiveVotable::ActiveVotable

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
lib/voruby/active_votable/active_votable.rb

Overview

ActiveVotable is a simple, but hopefully useful, database-backed VOTable parser. It uses LibXML’s SAX parser to extract the fields and data of a VOTable and loads those fields into a database table. This allows all the power of a full database manager + ActiveRecord to be used in searching and manipulating the VOTable. It assumes that the VOTable has one resource with one table and that the table is encoded as text and binary.

ActiveVotable.establish_connection(
 :adapter => 'postgresql'
 :database => 'votables'
 :host => 'localhost'
 :username => 'dbuser'
 :password => 'dbpassword')

ActiveVotable.build('test/active_votable/test.vot') do |vot|
  records = vot.find(:all, :conditions => ['survey LIKE ?', 'Deep Lens Survey'], :order => 'id')

  records = vot.page(10)

  vot.foreach_page do |page_num, records|
    puts "Page #{page_num}:"
    records.each do |rec|
      puts rec.inspect
    end
end

Constant Summary collapse

DATATYPE_CONVERSIONS =
{
  'boolean' => :boolean,
  'bit' => :integer,
  'unsignedByte' => :integer,
  'short' => :integer,
  'int' => :integer,
  'long' => :integer,
  'char' => :string,
  'unicodeChar' => :string,
  'float' => :float,
  'double' => :float,
  'floatComplex' => :string,
  'doubleComplex' => :string
}
@@end_of_cell =
true
@@arow =
[]
@@ordered_columns =
[]
@@items_per_page =
20
@@actions =
{
  :on_start_element => {
    'FIELD' => Proc.new { |name, attrs|
      field_name = ActiveVotable.columnize(attrs['name'] || attrs['ID'] || "unknown_column_#{rand(1000000)}")
      field_name = 'record_id' if field_name == 'id'
      field_type = ActiveVotable.column_type(attrs['datatype'] || 'char', attrs['arraysize'])
      @@ordered_columns << {:name => field_name, :type => field_type}
  
      ActiveRecord::Schema.define do
        add_column(ActiveVotable.table_name(), field_name, field_type)
      end
    },
    'TD' => Proc.new{ |name, attrs|
      @@end_of_cell = false
    }
  },
  :on_end_element => {
    'TR' => Proc.new { |name|
      row_def = {:resource_num => 1, :table_num => 1}
      @@ordered_columns.each_index do |i|
        row_def[@@ordered_columns[i][:name]] = cast(@@arow[i], @@ordered_columns[i][:type])
      end
      ActiveVotable.create(row_def)
      @@arow = []
    },
    'TD' => Proc.new { |name|
      @@end_of_cell = true
    }
  },
  :on_characters => Proc.new { |chars|
    @@arow << chars if !@@end_of_cell
  },
  :on_cdata_block => Proc.new{ |cdata|
    @@arow << cdata if !@@end_of_cell # not sure if this is safe
  }
}

Class Method Summary collapse

Class Method Details

.build(src, tbl_name = nil, &block) ⇒ Object

Parse a VOTable into a database table. If no table is specified, one will be created with the signature ‘votable_timestamp_randomnumber’. If the optional block is provided, ActiveVotable.drop() will be called automatically.

src:

The name of the VOTable file.

tbl_name:

The name of the database table to dump the VOTable into.



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/voruby/active_votable/active_votable.rb', line 154

def self.build(src, tbl_name=nil, &block)
  if block
    build(src, tbl_name)
    block.call(self)
    drop()
  else
    ActiveVotable.src = src
    ActiveVotable.parser = VOTableExtractor.new(src, @@actions)
    
    set_table_name(tbl_name || "votable_#{Time.now.to_i}_#{rand(1000000)}")
    
    create_basic_schema()
    parse()
    
    return self
  end
end

.cast(value, type) ⇒ Object

Given one of the types specified in ActiveRecord::ConnectionAdapters::TableDefinition.column casts a string into a corresponding value.



253
254
255
256
257
258
259
260
261
262
# File 'lib/voruby/active_votable/active_votable.rb', line 253

def self.cast(value, type)
  case type
  when :integer then value.to_i
  when :float then value.to_f
  when :string then value
  when :boolean
    (value != 'false' and value != '0') ? true: false
  else value
  end
end

.column_type(datatype, arraysize) ⇒ Object

Converts a VOTable datatype into a corresponding database column type. Typically you’ll never use this directly.



243
244
245
246
247
248
249
# File 'lib/voruby/active_votable/active_votable.rb', line 243

def self.column_type(datatype, arraysize)
  if arraysize
    :string
  else
    DATATYPE_CONVERSIONS[datatype] || :string
  end
end

.columnize(name) ⇒ Object

Converts a VOTable name or ID into a (hopefully) valid database column name. Typically you’ll never use this directly.



233
234
235
236
237
238
# File 'lib/voruby/active_votable/active_votable.rb', line 233

def self.columnize(name)
  name = name.downcase
  name['-'] = '_' if name =~ /-/
  name[/\W+/] = '_' if name =~ /\W+/
  name
end

.create_basic_schemaObject

All parsed VOTables will have a standard set of columns which are created by this method. Typically you’ll never use this directly.



212
213
214
215
216
217
218
219
220
221
# File 'lib/voruby/active_votable/active_votable.rb', line 212

def self.create_basic_schema
  ActiveRecord::Schema.define do
    create_table ActiveVotable::table_name(), :primary_key => 'id' do |t|
      t.column :resource_num, :integer, :null => false, :default => 1
      t.column :table_num, :integer, :null => false, :default => 1
    end

    add_index ActiveVotable::table_name(), [:resource_num, :table_num]
  end
end

.dropObject

Erase the table out of the database.



224
225
226
227
228
# File 'lib/voruby/active_votable/active_votable.rb', line 224

def self.drop
  ActiveRecord::Schema.define do
    drop_table ActiveVotable::table_name
  end
end

.establish_connection(config) ⇒ Object

Establish a connection to the database. See ActiveRecord::Base.establish_connection() for further details.



266
267
268
# File 'lib/voruby/active_votable/active_votable.rb', line 266

def self.establish_connection(config)
  self.superclass.establish_connection(config)
end

.find(*args) ⇒ Object

Works exactly as ActiveRecord.find() except that an additional option–:page–may be passed in. In that case :limit and :offset are ignored.



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/voruby/active_votable/active_votable.rb', line 273

def self.find(*args)
  options = extract_options_from_args!(args)
    
  if options.has_key?(:page)
    options[:limit] = items_per_page()
    options[:offset] = items_per_page() * (options[:page] - 1)
    options.delete(:page)
  end
    
  validate_find_options(options)
  set_readonly_option!(options)

  case args.first
    when :first then find_initial(options)
    when :all   then find_every(options)
    else             find_from_ids(args, options)
  end
end

.foreach_page(&block) ⇒ Object

Iterate through each page in the VOTable. The block receives the page number and the list of records.



301
302
303
304
305
306
307
# File 'lib/voruby/active_votable/active_votable.rb', line 301

def self.foreach_page(&block)
  num_pages = (count().to_f / items_per_page().to_f).ceil()
    
  (1..num_pages).each do |page_num|
    block.call(page_num, page(page_num))
  end
end

.foreach_record(&block) ⇒ Object

Iterate through each record in the votable.



310
311
312
313
314
# File 'lib/voruby/active_votable/active_votable.rb', line 310

def self.foreach_record(&block)
  find(:all, :order => 'id').each do |record|
    block.call(record)
  end
end

.items_per_pageObject

Get the number of records per page.



199
200
201
# File 'lib/voruby/active_votable/active_votable.rb', line 199

def self.items_per_page
  @@items_per_page
end

.items_per_page=(num) ⇒ Object

Set the number of records per page for use in paging results.



194
195
196
# File 'lib/voruby/active_votable/active_votable.rb', line 194

def self.items_per_page=(num)
  @@items_per_page = num
end

.page(page = 1) ⇒ Object

Retrieve the specified page. Applies to all rows in the VOTable.



294
295
296
# File 'lib/voruby/active_votable/active_votable.rb', line 294

def self.page(page=1)
  find(:all, :order => 'id', :page => page)
end

.parseObject

Parse the VOTable. Called automatically when you used ActiveVotable.build(). Typically you’ll never use this directly.



205
206
207
# File 'lib/voruby/active_votable/active_votable.rb', line 205

def self.parse
  parser().parse()
end

.parserObject

Get the XML parser in use.



189
190
191
# File 'lib/voruby/active_votable/active_votable.rb', line 189

def self.parser
  @@parser
end

.parser=(parser) ⇒ Object

Set the XML parser to use. Must of type VOTableExtractor. Typically you’ll never use this directly.



184
185
186
# File 'lib/voruby/active_votable/active_votable.rb', line 184

def self.parser=(parser)
  @@parser = parser
end

.srcObject

Get the file name of the source VOTable.



178
179
180
# File 'lib/voruby/active_votable/active_votable.rb', line 178

def self.src
  @@src
end

.src=(src) ⇒ Object

Set the file name of the source VOTable.



173
174
175
# File 'lib/voruby/active_votable/active_votable.rb', line 173

def self.src=(src)
  @@src = src
end