用Ruby制作标签的详细代码示例

30 阅读1分钟

了解如何通过 Cups/PPD API 在标签制作商上将推文转换为物理打印输出。这是一个愚蠢的概念,但通过与打印机接口,可以有一些很好的现实世界应用。

# Terminal
bundle add cupsffi
bundle add dotenv-rails
bundle add rufus-scheduler
WORKER=true bin/rails s
rails g model tweet tweet_id:integer:index tweeted_at:datetime username content:text printed:boolean
# irb
CupsPPD.new("Brother_QL_810W", nil).options
# .env
USER_ID=your-id-here
BEARER_TOKEN=your-token-here
# config/application.rb
Dotenv::Railtie.load
# config/initializers/cron.rb
require 'rufus/scheduler'

scheduler = Rufus::Scheduler.new

scheduler.every '1m' do
  Twitter.fetch if ENV['WORKER']
end
# models/printer.rb
require 'cupsffi'

class Printer
  def self.print(id)
    new(id).print
  end

  def initialize(id)
    @id = id
  end

  def print
    job = printer.print_data(text, "text/plain", options)
    loop do
      puts job.status
      break unless [:pending, :processing].include?(job.status)
      sleep 1
    end
    tweet.update(printed: true) if job.status == :completed
  end

  private

  def tweet
    @tweet ||= Tweet.find(@id)
  end

  def message
    [tweet.username, "said on", tweet.tweeted_at, ":", tweet.content].join(" ")
  end

  def printer

# models/twitter.rb
require 'net/http'
class Twitter
  USER_ID = ENV["USER_ID"]
  BEARER_TOKEN = ENV["BEARER_TOKEN"]

  def self.fetch
    new.fetch
  end

  def fetch
    Rails.logger.info "Fetching tweets #{Time.current}"

    return if tweets['data'].nil?
    tweets['data'].reverse.each do |tweet|
      user = tweets.dig('includes', 'users').find { |u| u['id'] == tweet['author_id'] }
      record = Tweet.find_or_create_by(
        tweet_id: tweet['id'],
        tweeted_at: tweet['created_at'],
        username: user['name'],
        content: tweet['text']
      )
      next if record.printed?
      Printer.new(record.id).print
    end
  end

  private

  def tweets
    @tweets ||= begin
      uri = URI(url)
      request = Net::HTTP::Get.new(uri)
      request["Authorization"] = "Bearer #{BEARER_TOKEN}"
      response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
        http.request(request)
      end
      JSON.parse(response.body)
    end
  end

  def url
    params = []
    params << "tweet.fields=created_at"
    params << "expansions=author_id"
    params << "since_id=#{last_tweet_id}" if last_tweet_id
    "https://api.twitter.com/2/users/#{USER_ID}/mentions?#{params.join("&")}"
  end

  def last_tweet_id
    @last_tweet_id ||= Tweet.order(tweet_id: :desc).first&.tweet_id
  end
end