class Transilien::MicroService

Constants

API_HOST
API_URI
Default_cache_duration

Attributes

caches[RW]
query_cache[RW]
access_time[RW]
external_code[RW]
name[RW]
payload[RW]

Public Class Methods

action() click to toggle source
# File lib/transilien/micro_service.rb, line 136
def action
  "#{action_component}List"
end
action_component() click to toggle source
# File lib/transilien/micro_service.rb, line 132
def action_component
  self.to_s.split('::').last 
end
action_instance_xpath() click to toggle source
# File lib/transilien/micro_service.rb, line 144
def action_instance_xpath
  "/Action#{action}/#{action}/#{action_component}"
end
action_param() click to toggle source
# File lib/transilien/micro_service.rb, line 140
def action_param
  "/?action=#{action}"
end
add_filters() click to toggle source
# File lib/transilien/micro_service.rb, line 179
def add_filters()
  self.filters
end
cache_it(item) click to toggle source
# File lib/transilien/micro_service.rb, line 98
def cache_it(item)
  @caches ||= {}
  cache_keys.each do |k|
    @caches[k] ||= {}
    @caches[k][item.send(k)] = item
  end
  item
end
cache_keys() click to toggle source
# File lib/transilien/micro_service.rb, line 94
def cache_keys
  [:name, :external_code]
end
errors(doc) click to toggle source
# File lib/transilien/micro_service.rb, line 117
def errors(doc)
  @errors ||= begin 
    @errors = []
    doc.xpath('/Errors/Error').each do |err_node|
      err = Transilien::MicroService::Error.new
      err.code = err_node['code']
      err.message = err_node.content
      err.request = { params: params, action: action_param}
      @errors << err
    end
    @errors
  end
end
filters() click to toggle source
# File lib/transilien/micro_service.rb, line 170
def filters
  @filters ||= {}
end
filters=(new_filters) click to toggle source
# File lib/transilien/micro_service.rb, line 174
def filters=(new_filters)
  raise ArgumentError.new('filters= -> new_filters MUST be a hash, even empty') unless new_filters.is_a?(Hash)
  @filters = new_filters
end
find(filters = {}, options = {}) click to toggle source

/?action=LineList&StopAreaExternalCode=DUA8754309;DUA8754513|and&RouteExternalCode=DUA8008030781013;DUA8008031050001|or -> find(:stop_area_external_code => { :and => ['DUA8754309', 'DUA8754513'] }, :route_external_code => { :or => ['DUA8008030781013', 'DUA8008031050001'] })

# File lib/transilien/micro_service.rb, line 57
def find(filters = {}, options = {})
  collection =   find_from_full_query_cache(filters)
  collection ||= find_from_query_caches(filters)

  self.filters = filters
  response = self.http.get(action_param, params)
  puts('== Request: ')
  puts(action_param.inspect)
  puts(params.inspect)
  puts(response.env[:url].inspect)
  body = response.body
  collection = []
  doc = Nokogiri.XML(body)
  return errors(doc) unless errors(doc).empty?
  request_time = Time.parse(response.headers[:date])
  doc.xpath(action_instance_xpath).each do |node|
    item = from_node(node, request_time)
    collection << item
  end
  @query_cache[filters.to_s] = { payload: collection, cached_at: request_time }
  collection
end
find_from_full_query_cache(filters) click to toggle source
# File lib/transilien/micro_service.rb, line 32
def find_from_full_query_cache(filters)
  @query_cache ||= {}
  if filters[:force_refresh]
    @query_cache.delete(filters.to_s)
  end
  if @query_cache[filters.to_s] && (@query_cache[filters.to_s][:cached_at].to_i + Default_cache_duration > Time.now.to_i)
    return @query_cache[filters.to_s][:payload]
  end
end
find_from_query_caches(filters, collection = nil, operator = nil) click to toggle source

Iterative search on per instance search. That's HARD. WIP idea: since filters are prefixed by operator (AND by default), we can deal key by key. Collection on the first run is the matching instances on that uniq key. The result will be the last collection returned. Potentially nil.

# File lib/transilien/micro_service.rb, line 45
def find_from_query_caches(filters, collection = nil, operator = nil)
  if collection.nil?
    # FIRST RUN
    filters.keys.each do |key|
      collection = [query_cache({key: key, value: filters[key]})]
    end
  end

end
from_node(node, access_time) click to toggle source
# File lib/transilien/micro_service.rb, line 80
def from_node(node, access_time)
  item = new
  item.payload = node

  # common stuff
  item.external_code = node["#{action_component}ExternalCode"]
  item.name = node["#{action_component}Name"]
  item.access_time = access_time

  cache_it(item)

  item
end
http(uri = API_URI) click to toggle source
# File lib/transilien/micro_service.rb, line 23
def http(uri = API_URI)
  @http ||= Faraday.new(:url => uri) do |faraday|
    # TODO give option to setup faraday
    faraday.request  :url_encoded             # form-encode POST params
    #faraday.response :logger                  # log requests to STDOUT
    faraday.adapter  Faraday.default_adapter  # make requests with Net::HTTP
  end
end
params() click to toggle source
# File lib/transilien/micro_service.rb, line 148
def params
  return {} if filters.empty?
  final = {}
  @filters.each do |filter, filter_value| 
    final_filter = filter.to_s.split('_').map(&:capitalize).join
    if filter_value.is_a?(Hash)
      filter_value.each_pair do |operator, values|
        ok_operators = [:and, :or]
        raise ArgumentError.new("Operator #{operator} unknown. Should be one of #{ok_operators.inspect}.") unless ok_operators.include?(operator.to_sym)
        final_values = [values].flatten.compact.join(';')
        final[final_filter] = "#{final_values}|#{operator.to_s}"
      end
    elsif filter_value.is_a?(Array)
      # By default, consider OR operator when values are only an array
      final[final_filter] = "#{filter_value.join(';')}|or"
    else
      final[final_filter] = filter_value
    end
  end
  final
end

Public Instance Methods

to_s() click to toggle source
# File lib/transilien/micro_service.rb, line 185
def to_s
  "#<#{self.class.to_s} external_code=#{@external_code.inspect} name=#{@name.inspect} >"
end