Class: PathTo::DescribedRoutes::Application

Inherits:
WithParams
  • Object
show all
Defined in:
lib/path-to/described_routes.rb

Overview

DescribedRoutes implementation of PathTo::Application.

Instance Attribute Summary collapse

Attributes inherited from WithParams

#params, #parent, #service

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from WithParams

#child, #complete_params_hash!, #extract_params, #respond_to?

Constructor Details

#initialize(options) ⇒ Application

Returns a new instance of Application.



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/path-to/described_routes.rb', line 190

def initialize(options)
  super(options[:parent], options[:service], options[:params])

  @base = options[:base]
  @base.sub(/\/$/, '') if base
  @default_type = options[:default_type] || TemplatedPath
  @http_client = options[:http_client] || HTTPClient
  @http_options = options[:http_options]
  
  @resource_templates = options[:resource_templates]
  unless @resource_templates
    if (json = options[:json])
      @resource_templates = ResourceTemplate::ResourceTemplates.new(JSON.parse(json))
    elsif (yaml = options[:yaml])
      @resource_templates = ResourceTemplate::ResourceTemplates.new(YAML.load(yaml))
    elsif (xml = options[:xml])
      @resource_templates = ResourceTemplate::ResourceTemplates.parse_xml(xml)
    end
  end
  
  if parent
    @base ||= parent.base
    @default_type ||= parent.default_type
    @http_client ||= parent.http_client
    @resource_templates ||= parent.resource_templates
    @http_options ||= parent.http_options
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object

Tries to respond to a missing method. We can do so if

  1. we have a resource template matching the method name

  2. #child_class_for returns a class or other factory object capable of creating a new child instance

Otherwise we invoke super in the hope of avoiding any hard-to-debug behaviour!



234
235
236
237
238
239
240
241
242
243
# File 'lib/path-to/described_routes.rb', line 234

def method_missing(method, *args)
  child_resource_template = resource_templates_by_name[method.to_s]
  if child_resource_template && (child_class = child_class_for(self, method, params, child_resource_template))
    positional_params, params_hash = extract_params(args, params)
    complete_params_hash!(params_hash, child_resource_template.positional_params(nil), positional_params)
    child(child_class, method, params_hash, child_resource_template)
  else
    super
  end
end

Instance Attribute Details

#baseObject (readonly)

Base URI of the application



138
139
140
# File 'lib/path-to/described_routes.rb', line 138

def base
  @base
end

#default_typeObject (readonly)

A Class (or at least something with a #new method) from which child objects will be created



132
133
134
# File 'lib/path-to/described_routes.rb', line 132

def default_type
  @default_type
end

#http_clientObject (readonly)

An HTTParty or similar



135
136
137
# File 'lib/path-to/described_routes.rb', line 135

def http_client
  @http_client
end

#http_optionsObject (readonly)

Hash of options to be included in HTTP method calls



141
142
143
# File 'lib/path-to/described_routes.rb', line 141

def http_options
  @http_options
end

#resource_templatesObject (readonly)

An Array of DescribedRoutes::Resource objects



129
130
131
# File 'lib/path-to/described_routes.rb', line 129

def resource_templates
  @resource_templates
end

Class Method Details

.discover(url, options = {}) ⇒ Object



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/path-to/described_routes.rb', line 143

def self.discover(url, options={})
  http_options = options[:http_options] || nil
  default_type = options[:default_type] || Path
  http_client  = options[:http_client]  || HTTPClient
  
   = self.(url, http_client)
  unless 
    raise ProtocolError.new("no metadata link found")
  end

  json = http_client.get(.href, :format => :text, :headers => {"Accept" => "application/json"})
  unless json
    raise ProtocolError.new("no json found")
  end

  self.new(options.merge(:json => json))
end


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/path-to/described_routes.rb', line 161

def self.(url, http_client)
  response = http_client.head(url, {"Accept" => "application/json"})
  unless response.kind_of?(Net::HTTPOK)
    raise ProtocolError.new("got response #{response.inspect} from #{url}")
  end
  link_header = LinkHeader.parse(response["Link"])

  app_templates_link = link_header.find_link(["rel", "describedby"], ["meta", "ResourceTemplates"])
  unless app_templates_link
    resource_template_link = link_header.find_link(["rel", "describedby"], ["meta", "ResourceTemplate"])
    if resource_template_link
      response = http_client.head(resource_template_link.href, {"Accept" => "application/json"})
      unless response.kind_of?(Net::HTTPOK)
        raise ProtocolError.new("got response #{response.inspect} from #{url}")
      end
      link_header = LinkHeader.parse(response["Link"])
      app_templates_link = link_header.find_link(["rel", "index"], ["meta", "ResourceTemplates"])
      unless app_templates_link
        raise ProtocolError.new("(2) couldn't find link with rel=\"index\" and meta=\"ResourceTemplates\" at #{resource_template_link.href}")
      end
    else
      unless app_templates_link
        raise ProtocolError.new("(1) couldn't find link with rel=\"described_by\" and meta=\"ResourceTemplates\" or meta=\"ResourceTemplate\" at #{url}")
      end
    end
  end
  app_templates_link
end

Instance Method Details

#[](params) ⇒ Object

Creates a copy of self with additional params



222
223
224
# File 'lib/path-to/described_routes.rb', line 222

def [](params)
  self.class.new(:parent => self, :params => params)
end

#applicationObject

Returns self. See TemplatedPath#application.



270
271
272
# File 'lib/path-to/described_routes.rb', line 270

def application
  self
end

#child_class_for(instance, method, params, template) ⇒ Object

Determines whether this application &/or its child objects should respond to the given method, and if so returns a class from which a new child instance (typically Path or a subclass thereof) will be created. This implementation (easily overridden) returns #default_type if there is a URI template defined for the method.

Parameters:

instance

This application or (presumably) one of its child objects

method

The method invoked on the instance that has (presumably) been intercepted by instance#method_missing

params

The instance’s params



256
257
258
# File 'lib/path-to/described_routes.rb', line 256

def child_class_for(instance, method, params, template)
  default_type
end

#resource_templates_by_nameObject

Returns a hash of all ResourceTemplates (the tree flattened) keyed by name



263
264
265
# File 'lib/path-to/described_routes.rb', line 263

def resource_templates_by_name
  @resource_templates_by_name ||= resource_templates.all_by_name
end