Rubyでスッキリとサービスクラス(モジュール)を作る
RubyでFoo.execute(args)
のように使えるクラスを作りたい。インタンス化は必要無い。内部で使うためのメソッドにはアクセスされたくない。
そしてできるだけスッキリ書きたい。
いいやり方ないかなと思っていましたが、ありました。
まず結論
定義側で
module Foo
extend self
def execute
bar
baz
...
end
private
def bar; ...; end
def baz; ...; end
end
呼び出し側で
Foo.execute # ok
Foo.bar # NoMethodError (private method `bar' called for Foo:Module)
Foo.baz # NoMethodError (private method `baz' called for Foo:Module)
参考にしたのは以下です:
これまでの模索
self.def
class Foo
def self.execute
bar
end
private
def self.bar; ...; end
end
※classでもmoduleでもどっちでも同じです
通常のクラスと同じように区切り線的にprivate
を置き、かつ全メソッドをself.method_name
の形式で書くかたちです。
メソッド定義の頭にself.
を付けていく必要があとはいえそこまで面倒でなく比較的スッキリしていますが...致命的な問題としてprivateが意味ありません。Foo.bar
が普通に呼べます。
メンバー内の性善説で「privateより下は外から呼ばない」として運用するのはアリです。
ただし設定によってはrubocopにprivate
が怒られるため、その場合はコメントで書くか他の手段で。
private_class_method
class Foo
def self.execute
bar
end
def self.bar; ...; end
private_class_method :bar
end
private_class_method
します。当然外からFoo.bar
は呼べません。
極めて正攻法で文法的に正しいのですが、private側のメソッド名を必ず2回書く必要があり面倒です。あとvimでメソッド名で*
したときに反応して邪魔です。
また筆者の好みですが「publicなものとprivateなものをprivate
という境界線によって視覚的に分離したい」という要求があり、その点が微妙です。
class << self
module Foo
class << self
def execute
bar
end
private
def bar; ...; end
end
end
privateでの区切りが意味をなしており、またself.
を都度書かなくなって良い、良いのだが...!
ファイルのほぼ全域のインデントが一段増えてしまうのがつらいです。惜しい。
一応、インデントを減らしたいだけであれば
module Foo; class << self
...
end;end
という手もありますが、謎ハック感があってちょっと...
そして再度結論
冒頭のコードを再掲します。
module Foo
extend self
def execute
bar
baz
...
end
private
def bar; ...; end
def baz; ...; end
end
module定義の先頭に簡素に一行extend self
を入れておくだけで、メソッド定義時に何か特別なことをするでもなく、公開メソッドと非公開メソッドをprivate
で区切ったかたちでスッキリと定義できます。変な書き方も無くインデントも増えません。
筆者はRailsでの開発でAPIラッパーやバッチ処理の本体などを書く際にこのかたちにするので、今後活用していけそうです。
やったね!
Author And Source
この問題について(Rubyでスッキリとサービスクラス(モジュール)を作る), 我々は、より多くの情報をここで見つけました https://zenn.dev/cumet04/articles/ruby-service-module著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Collection and Share based on the CC protocol