GraphQL はほとんど関係なく Ruby の話です。
GraphQL Ruby を実行する時はだいたいこんな感じで使う。
# app/graphql/my_schema.rb class MySchema < GraphQL::Schema # ... end # app/controllers/graphql_controller.rb result = MySchema.execute( params[:query], variables: params[:variables], context: { current_user: current_user }, ) render json: result
だが、MySchema
の親クラスである GraphQL::Schema
(lib/graphql/schema.rb) のコード を読んでもインスタンスメソッドの GraphQL::Schema#execute
しか定義されていない。
呼び出し側でどうして MySchema.execute(args)
のように特異メソッド的に呼べるのだろうと不思議だった。
以下が答えでした。
require 'forwardable' class MyClass alias :my_definition :itself def execute(arg) arg end class << self extend Forwardable def_delegator :my_definition, :execute def my_definition self.new end end end > MyClass.execute('hoge') #=> "hoge"
興奮した。
参考
instance method Object#itself (Ruby 2.6.0)
クラス/メソッドの定義/alias (Ruby 2.6.0)
module Forwardable (Ruby 2.6.0)
追記
alias :my_definition :itself
はこの例には余計だった。
lib/graphql/schema.rb
で定義している場所と理由。
こっちはもう少し調べないとわからなさそうです。
ていうかこの例に関していうと委譲がポイントでしたね。
require 'forwardable' class MyClass def execute(arg) arg end class << self extend Forwardable def_delegator :my_definition, :execute, :my_execute def my_definition self.new end end end > MyClass.my_execute('hoge') #=> "hoge" > MyClass.instance_methods(false) #=> [:execute] > MyClass.singleton_methods(false) #=> [:my_execute, :my_definition]
ちょっとスッキリしましたが、委譲難しい。
追記の参考
instance method Forwardable#def_delegator (Ruby 2.6.0)
instance method Module#instance_methods (Ruby 2.6.0)
instance method Object#singleton_methods (Ruby 2.6.0)
さらに追記
require 'forwardable' class MyClass alias :my_definition :itself def execute(arg) arg end class << self extend Forwardable def_delegator :my_definition, :execute, :my_execute def my_definition self.new end end end > MyClass.my_execute('hoge') #=> "hoge" > MyClass.instance_methods(false) #=> [:execute, :my_definition] > MyClass.singleton_methods(false) #=> [:my_execute, :my_definition]
alias :my_definition :itself
を追加することで、 MyClass#my_definition
が定義されるのか。
けっこうスッキリしたので、今日はここまでにしておきます。