Class: JSONRPC2::Interface

Inherits:
Object
  • Object
show all
Extended by:
TextileEmitter
Defined in:
lib/jsonrpc2/interface.rb

Overview

Base class for JSONRPC2 interface

Class Attribute Summary collapse

Authentication collapse

Rack-related collapse

DSL collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from TextileEmitter

about_method, method_to_textile, to_textile, to_textile_group

Constructor Details

#initialize(env) ⇒ Interface

Create new interface object

Parameters:

  • env (Hash)

    Rack environment



120
121
122
123
# File 'lib/jsonrpc2/interface.rb', line 120

def initialize(env)
  @_jsonrpc_env = env
  @_jsonrpc_request = Rack::Request.new(env)
end

Class Attribute Details

.aboutObject (readonly)

Returns the value of attribute about.



383
384
385
# File 'lib/jsonrpc2/interface.rb', line 383

def about
  @about
end

.typesObject (readonly)

Returns the value of attribute types.



383
384
385
# File 'lib/jsonrpc2/interface.rb', line 383

def types
  @types
end

Class Method Details

.___append_param(name, type, options) ⇒ Object

Store parameter in internal hash when building API



258
259
260
261
262
263
264
# File 'lib/jsonrpc2/interface.rb', line 258

def ___append_param name, type, options
  @params ||= []
  unless options.has_key?(:required)
    options[:required] = true
  end
  @params << options.merge({ :name => name, :type => type })
end

.auth_with(*args) ⇒ #check?

Get/set authenticator object for API interface - see Auth and BasicAuth

Parameters:

  • args (#check)

    An object that responds to check(environment, json_call_data)

Returns:

  • (#check, nil)

    Currently set object or nil



47
48
49
50
51
52
53
# File 'lib/jsonrpc2/interface.rb', line 47

def auth_with *args
  if args.empty?
    return @auth_with
  else
    @auth_with = args[0]
  end
end

.call(environment) ⇒ Array<Fixnum, Hash<String,String>, Array<String>>

Rack compatible call handler

Parameters:

  • environment (Hash)

    Rack environment hash

Returns:

  • (Array<Fixnum, Hash<String,String>, Array<String>>)

    Rack-compatible response



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/jsonrpc2/interface.rb', line 63

def call(environment)
  environment['json.request-id'] = Digest::MD5.hexdigest("#{$host ||= Socket.gethostname}-#{$$}-#{Time.now.to_f}")[0,8]
  request = Rack::Request.new(environment)
  catch :rack_response do
    best = JSONRPC2::HTTPUtils.which(environment['HTTP_ACCEPT'], %w[text/html application/json-rpc application/json])

    if request.path_info =~ %r'/_assets' or request.path_info == '/favicon.ico'
      best = 'text/html' # hack for assets
    end

    case best
    when 'text/html', 'text/css', 'image/png' # Assume browser
      monitor_time(environment, request.POST['__json__']) { JSONRPC2::HTML.call(self, request) }
    when 'application/json-rpc', 'application/json', nil # Assume correct by default
      environment['rack.input'].rewind
      raw = environment['rack.input'].read
      data = JSON.parse(raw) if raw.to_s.size >= 2
      monitor_time(environment, raw) { self.new(environment).rack_dispatch(data) }
    else
      [406, {'Content-Type' => 'text/html'},
        ["<!DOCTYPE html><html><head><title>Media type mismatch</title></head><body>I am unable to acquiesce to your request</body></html>"]]
    end
  end

rescue Exception => e
  if environment['rack.logger'].respond_to?(:error)
    environment['rack.logger'].error "#{e.class}: #{e.message} - #{e.backtrace * "\n    "}"
  end
  raise e.class, e.message, e.backtrace
end

.desc(str) ⇒ Object

Set description for next method



300
301
302
# File 'lib/jsonrpc2/interface.rb', line 300

def desc str
  @desc = str
end

.example(desc, code) ⇒ Object

Add an example for next method



305
306
307
308
# File 'lib/jsonrpc2/interface.rb', line 305

def example desc, code
  @examples ||= []
  @examples << { :desc => desc, :code => code }
end

.introduction(str = nil) ⇒ Object

Sets introduction for interface



345
346
347
# File 'lib/jsonrpc2/interface.rb', line 345

def introduction str = nil
  @introduction = str if str
end

.method_added(name) ⇒ Object

Catch methods added to class & store documentation



352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
# File 'lib/jsonrpc2/interface.rb', line 352

def method_added(name)
  return if self == JSONRPC2::Interface
  @about ||= {}
  method = {}
  method[:params] = @params if @params
  method[:returns] = @result if @result
  method[:desc] = @desc if @desc
  method[:examples] = @examples if @examples
  
  if method.empty?
    if public_methods(false).include?(name)
      unless @nodoc
        #logger.info("#{name} has no API documentation... :(")
      end
    else
      #logger.debug("#{name} isn't public - so no API")
    end
  else
    method[:name] = name
    method[:section] = @current_section
    method[:index] = @about.size
    @about[name.to_s] = method
  end

  @result = nil
  @params = nil
  @desc = nil
  @examples = nil
  @nodoc = false
end

.nodocObject

Exclude next method from documentation



335
336
337
# File 'lib/jsonrpc2/interface.rb', line 335

def nodoc
  @nodoc = true
end

.optional(name, type, desc = nil, options = nil) ⇒ Object

Define an optional parameter for next method



284
285
286
287
288
289
290
291
292
# File 'lib/jsonrpc2/interface.rb', line 284

def optional name, type, desc = nil, options = nil
  if options.nil? && desc.is_a?(Hash)
    options, desc = desc, nil
  end
  options ||= {}
  options[:desc] = desc if desc.is_a?(String)

  ___append_param(name, type, options.merge(:required => false))
end

.param(name, type, desc = nil, options = nil) ⇒ Object

Define a named parameter of type #type for next method

Parameters:

  • name (String)

    parameter name

  • type (String)

    description of type see Types



273
274
275
276
277
278
279
280
281
# File 'lib/jsonrpc2/interface.rb', line 273

def param name, type, desc = nil, options = nil
  if options.nil? && desc.is_a?(Hash)
    options, desc = desc, nil
  end
  options ||= {}
  options[:desc] = desc if desc.is_a?(String)
  
  ___append_param name, type, options
end

.result(type, desc = nil) ⇒ Object

Define type of return value for next method



295
296
297
# File 'lib/jsonrpc2/interface.rb', line 295

def result type, desc = nil
  @result = { :type => type, :desc => desc }
end

.section(name, summary = nil) ⇒ Object

Group methods



323
324
325
326
327
328
329
330
331
332
# File 'lib/jsonrpc2/interface.rb', line 323

def section name, summary=nil
  @sections ||= []
  @sections << {:name => name, :summary => summary}

  @current_section = name
  if block_given?
    yield
    @current_section = nil
  end
end

.title(str = nil) ⇒ Object

Set interface title



340
341
342
# File 'lib/jsonrpc2/interface.rb', line 340

def title str = nil
  @title = str if str
end

.type(name, *fields) ⇒ Object

Define a custom type



311
312
313
314
315
316
317
318
319
320
# File 'lib/jsonrpc2/interface.rb', line 311

def type name, *fields
  @types ||= {}
  type = JsonObjectType.new(name, fields)

  if block_given?
    yield(type)
  end

  @types[name] = type
end

Instance Method Details

#dispatch(rpc_data) ⇒ Hash, Array

Dispatch call to api method(s)

Parameters:

  • rpc_data (Hash, Array)

    Array of calls or Hash containing one call

Returns:

  • (Hash, Array)

    Depends on input, but either a hash result or an array of results corresponding to calls.



136
137
138
139
140
141
142
143
144
145
# File 'lib/jsonrpc2/interface.rb', line 136

def dispatch(rpc_data)
  result = case rpc_data
  when Array
    rpc_data.map { |rpc| dispatch_single(rpc) }
  else
    dispatch_single(rpc_data)
  end

  return result.to_json
end

#rack_dispatch(rpcData) ⇒ Object

Internal



125
126
127
128
129
130
# File 'lib/jsonrpc2/interface.rb', line 125

def rack_dispatch(rpcData)
  catch(:rack_response) do
    json = dispatch(rpcData)
    [200, {'Content-Type' => 'application/json-rpc'}, [json]]
  end
end