微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在“浏览”中:为 DNSSD::Service:Class 调用的私有方法“new”NoMethodError

如何解决在“浏览”中:为 DNSSD::Service:Class 调用的私有方法“new”NoMethodError

我在浏览 GitHub 时遇到了 https://github.com/PeterCrozier/AirPrint 并尝试了一下。 它是几年前写的,所以可能适用于旧版本的 ruby​​。我使用 macOS Big Sur 11.1 和 ruby​​ 2.6.3p62(2019-04-16 修订版 67580)[universal.x86_64-darwin20] 我对 ruby​​ 一无所知,但想看看是否可以获得一些帮助以使其正常工作。

当我运行 airprintfix.rb 时出现以下错误

Traceback (most recent call last):
    1: from ./airprintfix.rb:160:in `<main>'
./airprintfix.rb:19:in `browse': private method `new' called for DNSSD::Service:Class (NoMethodError)
#!/usr/bin/env ruby -rrubygems
#
require 'dnssd'
require 'timeout'
require 'optparse'

class Airprint

  attr_accessor :service,:domain,:script,:timeout

  def initialize
    self.service="_ipp._tcp"
    self.domain="local"
    self.script="airprintfix.sh"
    self.timeout=5
  end

  def browse(s=self.service,d=self.domain,t=self.timeout)
    browser = DNSSD::Service.new
    printers=[]
    t = Thread.new do
        puts "browsing for #{s} services in domain #{d}..."
        browser.browse s,d do |reply|
          resolver = DNSSD::Service.new
          resolver.resolve reply do |r|
            puts "Resolved #{r.name}"
            printers.push r
          end
        end
    end
    sleep self.timeout
    Thread.kill t
    # there might be more than one interface
    up = printers.uniq { |r| r.name }
    puts "Found #{up.count} unique from #{printers.count} entries" if up.count > 0
    up
  end

  def expand(fd,r,bg)
    # Expand out the Bonjour response
    puts "Service Name: #{r.name}\nResolved to: #{r.target}:#{r.port}\nService type: #{r.type}"
    txt = r.text_record
    # remove entry inserted by Bonjour
    txt.delete 'UUID'
    # Add Airprint txt fields
    txt['URF'] = 'none'
    txt['pdl'] = 'application/pdf,image/urf'
    txt.each_pair do |k,v|
      puts "\t#{k} = #{v}"
    end
    fd.write "#!/bin/bash\n\n"
    fd.write "dns-sd -R \"#{r.name} airprint\" _ipp._tcp,_universal . 631"
    txt.each_pair do |k,v|
      fd.write " \\\n\t#{k}=\'#{v}\'"
    end
    if bg
      fd.write ' &'
    end
    fd.puts
  end

end


options = {}
cmd = {}

OptionParser.new do |opts|
  opts.banner = "Usage: #{$0} [options] command"

  opts.separator ""
  opts.separator "Command: Choose only one"

  opts.on("-i","--install","install permanently,requires sudo") do |v|
    cmd[:install] = v
  end

  opts.on("-u","--uninstall","uninstall,requires sudo") do |v|
    cmd[:uninstall] = v
  end

  opts.on("-t","--test","test,use CTRL-C to exit") do |v|
    cmd[:test] = v
  end

  opts.separator ""
  opts.separator "Options:"

  opts.on("-f","--script_file","script filename") do |v|
    options[:script] = v
  end

  opts.on_tail("-h","--help","print this message") do
    puts opts
    exit
  end

end.parse!

if ARGV.count != 0 or cmd.count > 1
  puts "Bad command"
  exit
end


# require sudo to update /Library
isRoot = (Process.euid == 0)
if (cmd.key? :install or cmd.key? :uninstall) and !isRoot
  puts "Run with sudo to install or uninstall"
  exit
end

ap = Airprint.new

# plist for LaunchControl
hostname = `hostname`.strip.gsub(/\..*$/,'')
revhost = "local.#{hostname}.airprintfix"
launchlib = "/Library/launchdaemons"
launchfile=revhost + ".plist"

plist=<<EOT
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Label</key>
          <string>#{revhost}</string>
        <key>ProgramArguments</key>
          <array>
                  <string>/Library/launchdaemons/#{ap.script}</string>
          </array>
        <key>LowPriorityIO</key>
          <true/>
        <key>Nice</key>
          <integer>1</integer>
        <key>UserName</key>
          <string>root</string>
        <key>RunAtLoad</key>
          <true/>
        <key>Keeplive</key>
          <true/>
</dict>
</plist>
EOT



if cmd.key? :uninstall
  system "launchctl unload #{launchfile}"
  rc = $?.exitstatus
  puts "Uninstalling #{ap.script} from #{launchlib}"
  File.delete File.expand_path ap.script,launchlib
  puts "Uninstalling #{launchfile} from #{launchlib}"
  File.delete File.expand_path launchfile,launchlib
  exit rc
end


# determine existing printers
printers = ap.browse
count = printers.count
if count == 0
  puts "No shared printers were found"
  exit
end

# if not installing,create files in the working directory
wd = cmd.key?(:install) ? launchlib : "."

# write script to register them
bg = (count > 1)
f = File.expand_path(ap.script,wd)
File.open f,'w',0755 do |fd|
  printers.each { |r| ap.expand fd,bg }
end

# write a plist file to launch it
File.open File.expand_path(launchfile,wd),0644 do |fd|
  fd.write plist
end

if cmd.key? :install
  plist = File.expand_path(launchfile,wd)
  system "launchctl load -w #{plist}"
  rc = $?.exitstatus
  puts (rc == 0) ? "Installed" : "Failed to install #{plist},rc=#{rc}"
  exit rc
end

if cmd.key? :test
  puts "Registering printer,use CTRL-C when done"
  trap 'INT' do exit end
  system "/bin/bash #{ap.script}"
  exit $?.exitstatus
end

exit

任何想法是什么导致错误以及如何修复它?

谢谢!

吉姆

解决方法

你应该能够解决这个问题

  def browse(s=self.service,d=self.domain,t=self.timeout)
    browser = DNSSD::Service.new  #REMOVE  this line
    printers=[]
    t = Thread.new do
        puts "Browsing for #{s} services in domain #{d}..."
        DNSSD.browse s,d do |reply| #EDIT this Line
          resolver = DNSSD::Service.new #REMOVE this line 
          DNSSD.resolve reply do |r| #EDIT this Line
            puts "Resolved #{r.name}"
            printers.push r
          end
        end
    end
    sleep self.timeout
    Thread.kill t
    # there might be more than one interface
    up = printers.uniq { |r| r.name }
    puts "Found #{up.count} unique from #{printers.count} entries" if up.count > 0
    up
  end

似乎 DNSSD::Servicebrowseresolve 作为类实例方法公开,而 DNSSD 提供顶级 DSL 作为这些方法的传递。

这个库不是我写的,也不能确认其中包含的任何代码,但这会让你度过这个难关。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。