Tbpgr Blog

Ruby プログラマ tbpgr(てぃーびー) のブログ

RubyでPlugin機構のサンプルを実装してみる

alt

RubyでPlugin機構のサンプルを実装してみます。

参考

設計の参考となる情報は以下の記事にまとまっています。

tbpgr.hatenablog.com

仕様

  • 任意のフォーマットに変換したテキストを出力する
  • 入力テキストを引数にあたえる
  • 適用フォーマットのリストを引数に与える
  • 存在しないフォーマッターを指定した場合は何もしない

設計方針

  • フォーマットはPlugin化されている
  • フォーマットのPluginのファイル名は formatters/XXXX-formatter.rb の命名ルールに従うこと
  • フォーマットのPluginのクラス名は XXXXFormatter の命名ルールに従うこと
  • フォーマットのPluginは MessageViewer::Formatters::BaseFormatter を継承すること

Core gem

構成

├── Gemfile
├── Gemfile.lock
├── README.md
├── Rakefile
├── lib
│   ├── formatters
│   │   ├── base_formatter.rb
│   │   ├── plain_formatter.rb
│   │   ├── twice_formatter.rb
│   │   └── upper_formatter.rb
│   ├── formatters.rb
│   └── textviewer.rb
├── spec
│   ├── spec_helper.rb
│   └── textviewer_spec.rb
└── textviewer.gemspec

lib/textviewer.rb

エントリーポイント。
MessageViewer::Viewer.run で文字列出力処理を実行する。

require 'rubygems'

module MessageViewer
  def self.formatters
    @formatters ||= {}
  end

  class Viewer
    def self.run(text, formatters)
      load_formatters
      formatters.map{|e|MessageViewer.formatters[e]}
                .compact
                .reduce(text){|a, f|f.display(a)}
    end

    private

    def self.load_formatters
      ::Gem.find_files('formatters/*_formatter.rb').each { |formatter| require formatter }
    end
  end
end
require 'formatters'

lib/formatters/base_formatter.rb

Formatter Pluginの基底クラス。
継承時に Plugin を MessageViewer に登録する。

module MessageViewer
  module Formatters
    class BaseFormatter
      def self.inherited(child)
        child.name =~ /^.*Formatters::(?<plugin_name>.*)Formatter$/
        key = Regexp.last_match[:plugin_name].downcase.to_sym
        MessageViewer.formatters[key] = child
      end
    end
  end
end

lib/formatters/upper_formatter.rb

文字列を大文字化する組み込み Plugin Formatter。

require "formatters/base_formatter"

module MessageViewer
  module Formatters
    class UpperFormatter < BaseFormatter
      def self.display(text)
        text.upcase
      end
    end
  end
end

その他のコード

その他のコードは省略します。
気になる方は

tbpgr/textviewer - GitHub

をご確認ください。

Plugin gem

構成

├── Gemfile
├── README.md
├── Rakefile
├── bin
│   ├── console
│   └── setup
├── lib
│   └── formatters
│       └── lower_formatter.rb
└── textviewer-lower.gemspec

textviewer-lower.gemspec

# 略
spec.add_runtime_dependency 'textviewer'
# 略

lib/formatters/lower_formatter.rb

文字列を小文字化する組み込み Plugin Formatter。

require 'textviewer'

module MessageViewer
  module Formatters
    class LowerFormatter < BaseFormatter
      def self.display(text)
        text.downcase
      end
    end
  end
end

テスト

  • Lower Plugin 追加前

lower をインストールしていないので無視されて、大文字の結果が返却されています

$ gem list textviewer

*** LOCAL GEMS ***

textviewer (0.0.1)
require 'pp'
pp MessageViewer.formatters
print MessageViewer::Viewer.run('hOgE', [:plain, :twice, :upper, :lower])

# {:plain=>MessageViewer::Formatters::PlainFormatter,
# :twice=>MessageViewer::Formatters::TwiceFormatter,
# :upper=>MessageViewer::Formatters::UpperFormatter}
# HOGEHOGE
  • Lower Plugin 追加後

lower をインストールしているので無視されて、小文字の結果が返却されています

$ cd textviewer-lower
$ rake install:local
textviewer-lower 0.0.1 built to pkg/textviewer-lower-0.0.1.gem.
textviewer-lower (0.0.1) installed.

$ gem list textviewer

*** LOCAL GEMS ***

textviewer (0.0.1)
textviewer-lower (0.0.1)
require 'textviewer'
require 'pp'
require 'rubygems'
pp MessageViewer.formatters
print MessageViewer::Viewer.run('hOgE', [:plain, :twice, :upper, :lower])
pp MessageViewer.formatters

# {:plain=>MessageViewer::Formatters::PlainFormatter,
#  :twice=>MessageViewer::Formatters::TwiceFormatter,
#  :upper=>MessageViewer::Formatters::UpperFormatter}
# hogehoge{:plain=>MessageViewer::Formatters::PlainFormatter,
#  :twice=>MessageViewer::Formatters::TwiceFormatter,
#  :upper=>MessageViewer::Formatters::UpperFormatter,
#  :lower=>MessageViewer::Formatters::LowerFormatter}

関連資料