4
\$\begingroup\$

At work we have a need to know what printers are getting dangerously low on their toner, and paper consumption, etc..

So I've created a program that pulls the printer information off the websites the printers are located at and outputs the information. This program has the option to use two separate flags -e for every printer (couldn't get -a to work) and -p to specify the printer.

What this program does is pull the printer name and type off of a YAML file, use Nokogiri to pull information off the websites by grabbing, correctly, the css selector that is containing the information, from there it runs through a regex, and outputs the information.

If the user specifies the printer using the -p flag it pulls the printer name and the printer type off a YAML file, sends the printer name, based on the users choice, to the correct method to parse the website, from there it uses Nokogiri and parses the site, grabbing the correct information

What I want is a way to clean this up a bit, it's a little smelly if you know what I mean and I would like to possibly create a function for all the printing I'm doing?

Source code:

#!/usr/local/bin/ruby

require 'colored'
require 'nokogiri'
require 'restclient'
require 'optparse'
require 'yaml'

def print_usage
  "USAGE: #{File.basename(__FILE__)} -[ehu] -[p] <printer-name>".yellow.bold
end

OPTIONS = Struct.new(:printer, :all)

class PrinterManager

  attr_accessor :printer, :all

  def self.parse(options)
    args = OPTIONS.new
    opt_parser = OptionParser.new do |opts|
      opts.banner = print_usage
      opts.on("-pPRINTER", "--printer=PRINTER", "Pass the printer name") do |p|
        args.printer = p
      end
      opts.on("-e", "--everything", "Run on all printers") do
        args.all = true
      end
      opts.on("-u", "--usage", "Print usage page") do
        puts print_usage
        exit
      end
      opts.on("-h", "--help", "Prints this help") do
        puts opts
        exit
      end
    end
    opt_parser.parse!(options)
    return args
  end

  def ping
    ping_printer = `ping -c 1 #{@printer}`[/1 packet/]
    if ping_printer == "1 packet"
      puts "Printer: #{@printer} connected to network".blue.bold
    else
      raise LoadError.new("Printer: #{@printer} failed to ping; check network connection.".red.bold)
      exit
    end
  end

  def page(site)
    Nokogiri::HTML(RestClient.get(site))
  end

  def check_toner(toner)
    if toner == nil
      puts "Unknown cartridge installed".blue.bold
    else
      if toner >= "30" || toner == "Contrast"
        puts "Toner Level: Adequate".green.bold
      elsif toner <= "30" || toner == "Toner Low"
        puts "Toner Level: Low".yellow.bold
      else
        puts "Printer: #{@printer} out of toner, replace toner.".red.bold
      end
    end
  end

  def hp_color
    ping
    parsing = page("#{@printer}.adfitech.com")
    print "Black Toner Level: ", parsing.css('.consumable-block')[0].to_s[/\d{1,3}[%]/], "\n"
    print "Cyan Toner Level: ", parsing.css('.consumable-block')[1].to_s[/\d{1,3}[%]/], "\n"
    print "Magenta Toner Level: ", parsing.css('.consumable-block')[2].to_s[/\d{1,3}[%]/], "\n"
    print "Yellow Toner Level: ", parsing.css('.consumable-block')[3].to_s[/\d{1,3}[%]/], "\n"
    print "Fuser: ", parsing.css('.consumable-block')[4].to_s[/\d{1,3}[%]/], "\n"
  end

  def hp_4100
    ping
    parsing = page("#{@printer}.com")
    maint = page("http://hp/device/this.LCDispatcher?dispatch=html&cat=0&pos=2")
    toner = parsing.css('font')[28].to_s[/\d{1,3}[%]/]
    check_toner(toner)
    puts "Maint Kit: #{maint.css('font')[19].text}"
    powersave = parsing.css('td')[9].to_s[/(?<=POWERSAVE\ )\w+(?=<)/]
    powersave == "ON" ? (puts "Powersave Mode: ON") : (puts "Powersave Mode: OFF")
  end

  def hp_4200
    ping
    parsing = page("http://#{@printer}.com/hp/device/this.LCDispatcher")
    toner = parsing.css('font')[30].to_s[/\d{1,3}[%]/]
    check_toner(toner)
    print "Maint Kit: ", parsing.css('font')[32].text[/\d{1,3}[%]/], "\n"
  end

  def hp_4250
    ping
    parsing = page("#{@printer}.com/hp/device/this.LCDispatcher")
    toner = parsing.css('.hpConsumableBlockHeaderText')[0].to_s[/\d{1,3}[%]/]
    check_toner(toner)
    print "Maint Kit: ", parsing.css('.hpConsumableBlockHeaderText')[1].to_s[/\d{1,3}[%]/], "\n"
  end

  def hp_4350
    ping
    parsing = page("#{@printer}.com/hp/device/this.LCDispatcher?nav=hp.Supplies")
    toner = parsing.css('.hpConsumableBlockHeaderText')[1].text[/\d{1,3}[%]/]
    check_toner(toner)
    print "Maint kit: ", parsing.css('.hpConsumableBlockHeaderText')[3].text[/\d{1,3}[%]/], "\n"
    print "Pages Remaining: ", parsing.css('.hpPageText')[4].text[/\d{1,10}/], "\n"
  end

  def hp_cp4005
    ping
    parsing = page("#{@printer}.com/hp/device/this.LCDispatcher")
    print "Black Toner Level: ", parsing.css('.hpConsumableBlockHeaderText')[0].to_s[/\d{1,3}[%]/], "\n"
    print "Cyan Toner LeveL: ", parsing.css('.hpConsumableBlockHeaderText')[1].to_s[/\d{1,3}[%]/], "\n"
    print "Magenta Toner Level: ", parsing.css('.hpConsumableBlockHeaderText')[2].to_s[/\d{1,3}[%]/], "\n"
    print "Yellow Toner Level: ", parsing.css('.hpConsumableBlockHeaderText')[3].to_s[/\d{1,3}[%]/], "\n"
    print "Image Trans Kit: ",  parsing.css('.hpConsumableBlockHeaderText')[4].to_s[/\d{1,3}[%]/], "\n"
    print "Fuser: ", parsing.css('.hpConsumableBlockHeaderText')[5].to_s[/\d{1,3}[%]/], "\n"
  end

  def brother_8110
    ping
    check_mode = page("#{@printer}.com/general/status.html")
    parsing = page("#{@printer}.adfitech.com/general/information.html?kind=item")
    powersave = check_mode.css('dd')[0].to_s[/Sleep/]
    powersave == "Sleep" ? (puts "Powersave Mode: ON") : (puts "Powersave Mode: OFF")
    print "Drum Kit: ", parsing.css('dd')[7].to_s[/\d{5,7}/], " pages remaining | ", parsing.css('dd')[8].to_s[/\d{1,3}\.\d{2}[%]/], " life remaining\n"
    print "Fuser: ", parsing.css('dd')[11].to_s[/\d{1,10}/], " pages remaining | ", parsing.css('dd')[16].to_s[/\d{1,3}\.\d{2}[%]/], " life remaining\n"
  end

  def brother_8080
    ping
    parsing = page("#{@printer}.com/etc/mnt_info.html?kind=item")
    toner_check = page("#{@printer}.com/main/main.html")
    toner = toner_check.css('a')[14].text[/\w+/]
    check_toner(toner)
    print "Drum Kit: ", parsing.css('.elem')[7].to_s[/\d{1,10}/], " pages remaining | ", parsing.css('.elem')[8].to_s[/\d{1,3}\.\d{2}[%]/], " life remaining\n"
    print "Fuser: ",  parsing.css('.elem')[9].to_s[/\d{1,10}/], " pages remaining | ", parsing.css('.elem')[10].to_s[/\d{1,3}\.\d{2}[%]/], " life remaining\n"
  end
end

mr_clean = PrinterManager.new
options = PrinterManager.parse(ARGV)

if options.printer
  file = YAML.load_file("printerlist.yml")
  @printer = mr_clean.printer = options.printer
  mr_clean.send("#{file['printers'][@printer]}")
elsif options.all
  file = YAML.load_file("printerlist.yml")
  file['printers'].each do |printer, method|
    @printer = mr_clean.printer = printer
    case
    when method =~ /brother/i
      mr_clean.send("#{method}")
    when method =~ /hp/i
      mr_clean.send("#{method}")
    end
  end
else
  abort(print_usage)
end

YAML file:

printers: 
 acct-jet: 'brother_8080'
 admin-jet: 'brother_8080'
 cdprt11: 'brother_8080'
 closing-2: 'hp_4250'
 credjet: 'brother_8080'
 devlcolor: 'hp_cp4005'
 devljet: 'hp_4250'
 doc-jet: 'hp_4250'
 hr-jet: 'hp_4350'
 laser01: 'hp_4350'
 laser02: 'hp_4250'
 laser03: 'hp_4350'
 laser04: 'hp_4200'
 laser05: 'hp_4250'
 laser06: 'hp_4350'
 laser07: 'brother_8110'
 laser09: 'hp_4200'
 laser10: 'hp_4350'
 laser13: 'brother_8080'
 laser14: 'hp_4250'
 laser16: 'brother_8080'
 laser18: 'hp_4350'
 laser20: 'hp_4350'
 laser21: 'hp_4350'
 laser22: 'brother_8080'
 laser23: 'hp_4350'
 laser24: 'hp_4250'
 laser25: 'hp_4200'
 laser26: 'hp_4350'
 laser27: 'hp_4350'
 laser28: 'hp_4350'
 laser29: 'hp_4250'
 laser30: 'brother_8110'
 laser31: 'hp_4350'
 laser32: 'hp_4100'
 laser33: 'brother_8110'
 laser34: 'hp_4350'
 laser35: 'brother_8080'
 laser36: 'hp_4250'
 laser37: 'hp_4200'
 laser38: 'hp_4350'
 laser39: 'hp_4350'
 laser40: 'brother_8080'
 laser41: 'hp_4350'
 laser42: 'hp_4200'
 laser43: 'brother_8080'
 laser44: 'brother_8080'
 lasercolor1: 'hp_color'
 mailrm2: 'brother_8080'
 mailrm4: 'brother_8080'
 npl-3: 'hp_4350'
 ops-jet: 'brother_8080'
 pref-jet: 'hp_4200'
 qc-color: 'hp_color'
 qc-cust: 'brother_8080'
 qc-cust2: 'brother_8080'
 qc-cust3: 'brother_8080'
 qc-cust4: 'brother_8080'
 qcmktg: 'brother_8080'
 ship-admin: 'brother_8080'
 ship-admin2: 'brother_8080'
 ship-audit: 'hp_4200'
 ship-setup2: 'brother_8110'
 ship-setup3: 'hp_4200'
 stephjet: 'hp_4350'
 team-d: 'hp_4200'
 team-e: 'hp_4350'
 team-f: 'hp_4350'
 team-t: 'hp_4200'
 verif-jet: 'hp_4350'
 verif-jet2: 'hp_4200'  

Examples of usage:

[]$ clean_printer -e # -e flag
Printer: acct-jet connected to network
Toner Level: Adequate
Drum Kit: 19051 pages remaining | 78.00% life remaining
Fuser: 46149 pages remaining | 48.00% life remaining
Printer: admin-jet connected to network
Toner Level: Adequate
Drum Kit: 8969 pages remaining | 36.00% life remaining
Fuser: 33652 pages remaining | 34.00% life remaining
Printer: cdprt11 connected to network
Toner Level: Adequate
Drum Kit: 19078 pages remaining | 78.00% life remaining
Fuser: 50905 pages remaining | 52.00% life remaining
Printer: closing-2 connected to network
Toner Level: Adequate
Maint Kit: 78%

[]$ clean_printer -p laser32 #specific printer
Printer: laser32 connected to network
Toner Level: Adequate
Maint Kit: 100%
Powersave Mode: ON
\$\endgroup\$
  • 1
    \$\begingroup\$ Simpler refactor: use hashes to map printers to features and tests, and then use that hash when printing. Better refactor: create a base class for printers, with a print method that tests whether the printer has various features, and subclass that for the implementation variations for detecting if a printer has a feature and what its value is. \$\endgroup\$ – Phrogz Feb 18 '16 at 15:24
  • \$\begingroup\$ In what way you think to refactor this code (script-like or OOP-way)? Now class PrinterManager is not actually a class. It behaves more like namespace (module) with set of methods with lots of puts's. And @printer outside class is confusing. \$\endgroup\$ – Sergii K Feb 18 '16 at 18:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.