D5145c421cd25af6fa577c15219add90

I've put together a quick ruby bluetooth class. All it does at the moment is search for devices and send files to any selected device (which is all I need). It uses system commands, which isn't ideal, but I can't really see a better way. The main bits which need refactoring are the bits where I mess about with the new method... not sure what can be done here, and the find_new class method, which scans for devices and returns an array of Device objects (I'm terrible with regular expressions).

class Device
  @@all = Array.new
  
  attr_reader :mac, :name
  
  # need this funny bit to alias class methods
  class << self
    alias_method :old_new, :new
  end

  # if the device is already listed in all_devices, return the
  # existing object instead of creating a new one
  def self.new *args, &b
    @@all.each do |device|
      return device if args.first == device.mac
    end
    this = self.old_new *args, &b
    @@all << this
    this 
  end

  def initialize mac, name
    @mac = mac
    @name = name
    @sent = {}
  end

  def sent? file
    @sent[file]
  end
  
  def send! file, timeout=8
    result = `ussp-push --timeo #{timeout} #{@mac}@ #{file} #{file.name}`
    @sent[file] = ($?.to_i == 0 && result.scan(/Connection established/))
  end

  def self.find_new
    device_objects = Array.new
    devices_string = `hcitool scan --flush`
    available_devices = devices_string.scan(/[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]\t[^\n]*/i)
    available_devices.each do |detected_device|
      mac_addr = detected_device.scan(/[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]/i).first
      dev_name = detected_device.scan(/\t[^\n]*/i).first.gsub(/\t/,'')
      new_device = Device.new mac_addr, dev_name
      device_objects << new_device
    end
    device_objects
  end
end

Refactorings

No refactoring yet !

A74c34f1043b833b1fcc86ce9f3521ee

Pavel Gorbokon

April 6, 2010, April 06, 2010 20:39, permalink

1 rating. Login to rate!

Instead of aliasing new you can just call super

class Device
  @@devices = {}

  def self.new mac, *args
    @@devices[mac] ||= super
  end

  MAC_PATTERN = /(?:[0-9a-f]{2}\:){5}[0-9a-f]{2}/
  NAME_PATTERN = /[^\n]*/
  DEVICE_SCAN_REGEXP = /(#{MAC_PATTERN})\t(#{NAME_PATTERN})/

  def self.find_new
    devices = `hcitool scan --flush`
    devices.scan(DEVICE_SCAN_REGEXP).map do |(mac, name)|
      Device.new mac, name
    end
  end

  attr_reader :mac, :name
  
  def initialize mac, name
    @mac, @name = mac, name
    @sent = {}
  end

  def sent? file
    @sent[file]
  end

  def send! file, timeout=8
    result = `ussp-push --timeo #{timeout} #{@mac}@ #{file} #{file.name}`
    @sent[file] = ($?.to_i == 0 && result.scan(/Connection established/))
  end
end
D5145c421cd25af6fa577c15219add90

Nathan

April 7, 2010, April 07, 2010 08:34, permalink

No rating. Login to rate!

I like what you've done with both methods. The map method is one that I should remember for future, but what you did with the new method and the class level array is just plain clever.

Your refactoring





Format Copy from initial code

or Cancel