Module: Gienah::Plugin

Defined in:
lib/gienah/plugin.rb,
sig/gienah.rbs

Class Method Summary collapse

Class Method Details

.call(method, params = {}) ⇒ Object

Parameters:

  • method (String)
  • params (json) (defaults to: {})

Returns:

  • (Object)

Raises:



23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/gienah/plugin.rb', line 23

def call(method, params = {})
  raise LifecycleError, "plugin is not running" unless running?

  id = next_id
  write(Protocol.request(id, method, params))
  loop do
    message = Protocol.read(@input)
    raise Error, "host closed the connection" unless message
    return response_value(message) if message["id"] == id && !message.key?("method")

    dispatch(message)
  end
end

.capability?(name) ⇒ Boolean

Parameters:

  • name (String)

Returns:

  • (Boolean)


44
45
46
# File 'lib/gienah/plugin.rb', line 44

def capability?(name)
  @capabilities.include?(name.to_s)
end

.dispatch(message) ⇒ Object



96
97
98
99
100
101
102
103
104
# File 'lib/gienah/plugin.rb', line 96

def dispatch(message)
  if message.key?("method")
    if message.key?("id")
      write(handle_request(message))
    else
      handle_notification(message)
    end
  end
end

.export(name) {|arg0| ... } ⇒ nil

Parameters:

  • name (String)

Yields:

Yield Parameters:

  • arg0 (json)

Yield Returns:

  • (Object)

Returns:

  • (nil)

Raises:

  • (ArgumentError)


7
8
9
10
11
12
13
# File 'lib/gienah/plugin.rb', line 7

def export(name, &handler)
  raise ArgumentError, "name must be a nonempty String" unless name.is_a?(String) && !name.empty?
  raise ArgumentError, "handler required" unless handler

  exports[name] = handler
  nil
end

.exports ⇒ Object



75
76
77
# File 'lib/gienah/plugin.rb', line 75

def exports
  @exports ||= {}
end

.handle_notification(message) ⇒ Object



128
129
130
# File 'lib/gienah/plugin.rb', line 128

def handle_notification(message)
  listeners.fetch(message["method"], []).each { |listener| listener.call(message.fetch("params", {})) }
end

.handle_request(message) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/gienah/plugin.rb', line 106

def handle_request(message)
  method = message["method"]
  params = message.fetch("params", {})
  case method
  when "initialize"
    @capabilities = Array(params["capabilities"]).map(&:to_s).freeze
    Protocol.response(message["id"], result: {"api_version" => params["api_version"]})
  when "shutdown"
    @stopped = true
    Protocol.response(message["id"], result: nil)
  else
    handler = exports[method]
    unless handler
      return Protocol.response(message["id"], error: {"code" => -32601, "message" => "method not found: #{method}"})
    end
    result = handler.arity == 1 ? handler.call(params) : handler.call(self, params)
    Protocol.response(message["id"], result: result)
  end
rescue StandardError => error
  Protocol.response(message["id"], error: {"code" => -32000, "message" => "#{error.class}: #{error.message}"})
end

.listeners ⇒ Object



79
80
81
# File 'lib/gienah/plugin.rb', line 79

def listeners
  @listeners ||= Hash.new { |hash, key| hash[key] = [] }
end

.next_id ⇒ Object



87
88
89
# File 'lib/gienah/plugin.rb', line 87

def next_id
  @sequence = (@sequence || 0) + 1
end

.notify(method, params = {}) ⇒ nil

Parameters:

  • method (String)
  • params (json) (defaults to: {})

Returns:

  • (nil)

Raises:



37
38
39
40
41
42
# File 'lib/gienah/plugin.rb', line 37

def notify(method, params = {})
  raise LifecycleError, "plugin is not running" unless running?

  write(Protocol.notification(method, params))
  nil
end

.on(event) {|arg0| ... } ⇒ nil

Parameters:

  • event (String)

Yields:

Yield Parameters:

  • arg0 (json)

Yield Returns:

  • (Object)

Returns:

  • (nil)

Raises:

  • (ArgumentError)


15
16
17
18
19
20
21
# File 'lib/gienah/plugin.rb', line 15

def on(event, &handler)
  raise ArgumentError, "event must be a nonempty String" unless event.is_a?(String) && !event.empty?
  raise ArgumentError, "handler required" unless handler

  listeners[event] << handler
  nil
end

.reset! ⇒ Object



66
67
68
69
70
71
72
73
# File 'lib/gienah/plugin.rb', line 66

def reset!
  @exports = {}
  @listeners = Hash.new { |hash, key| hash[key] = [] }
  @capabilities = []
  @sequence = 0
  @running = false
  nil
end

.response_value(message) ⇒ Object

Raises:



132
133
134
135
136
# File 'lib/gienah/plugin.rb', line 132

def response_value(message)
  raise Error, message.fetch("error").fetch("message") if message.key?("error")

  message["result"]
end

.run(input: $stdin, output: $stdout) ⇒ nil

Parameters:

  • input: (IO) (defaults to: $stdin)
  • output: (IO) (defaults to: $stdout)

Returns:

  • (nil)


48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/gienah/plugin.rb', line 48

def run(input: $stdin, output: $stdout)
  @input = input
  @output = output
  @input.binmode if @input.respond_to?(:binmode)
  @output.binmode if @output.respond_to?(:binmode)
  @running = true
  loop do
    message = Protocol.read(@input)
    break unless message

    dispatch(message)
    break if @stopped
  end
  nil
ensure
  @running = false
end

.running? ⇒ Boolean

Returns:

  • (Boolean)


83
84
85
# File 'lib/gienah/plugin.rb', line 83

def running?
  !!@running
end

.write(message) ⇒ Object



91
92
93
94
# File 'lib/gienah/plugin.rb', line 91

def write(message)
  @output.write(Protocol.frame(message))
  @output.flush
end