Module: Betterific::ProtobufClient

Extended by:
ClientHelpers
Includes:
ClientConstants
Defined in:
lib/betterific/protobuf_client.rb

Constant Summary collapse

LAST_REFRESH =

Cache of the last time a schema was refreshed by name.

{}
PROTO_SCHEMA_CACHE =

Cache of schemas by URI.

{}
PROTO_TTL_SECONDS =

How many seconds to keep a schema before refreshing.

60

Constants included from ClientConstants

ClientConstants::BASE_URL, ClientConstants::BETTERIFS_BASE_URL, ClientConstants::PROTO_PACKAGE_NAME, ClientConstants::SEARCH_BASE_URL, ClientConstants::TAGS_BASE_URL, ClientConstants::TMP_DIR, ClientConstants::USERS_BASE_URL

Class Method Summary collapse

Class Method Details

.betterifs(opts = {}) ⇒ Object

Get a list of betterifs.

Parameters

  • opts - If most_popular, gets the most popular betterifs of the last week.

    If most_recent, gets the most recent betterifs.

    => [id0, id1, …, idx] specifies the ids of the betterif(s) to return.



98
99
100
101
102
103
104
105
106
107
108
# File 'lib/betterific/protobuf_client.rb', line 98

def self.betterifs(opts={})
  if [:most_popular, 'most_popular'].include?(opts) || (opts.is_a?(Hash) && [:most_popular, 'most_popular'].include?(opts[:filter]))
    return get_protobuf("#{BETTERIFS_BASE_URL}/most-popular")
  elsif [:most_recent, 'most_recent'].include?(opts) || (opts.is_a?(Hash) && [:most_recent, 'most_recent'].include?(opts[:filter]))
    return get_protobuf("#{BETTERIFS_BASE_URL}/most-recent")
  elsif opts[:ids]
    return get_protobuf("#{BETTERIFS_BASE_URL}?betterifs[ids]=#{Array(opts[:ids]).map(&:to_s).join(',')}")
  else
    raise "No filter and no ids given."
  end
end

.compile_and_load_string(kode, url) ⇒ Object

:nodoc



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/betterific/protobuf_client.rb', line 15

def compile_and_load_string(kode, url) #:nodoc
  unless Dir.exists?(self::TMP_DIR)
    Dir.mkdir(self::TMP_DIR, 0700)
  end
  deps = fetch_and_save_dependencies(kode, url)
  fname = url.split(/\//)[-1]
  File.open(File.join(self::TMP_DIR, fname), 'w') do |f|
    f.write(kode)
  end
  deps << fname
  deps = deps.reject do |d|
    Kernel.const_defined?(self::PROTO_PACKAGE_NAME.to_sym) && Kernel.const_get(self::PROTO_PACKAGE_NAME.to_sym)
      .const_defined?(d.gsub(/\.proto$/, '').camelize.to_sym)
  end
  unless deps.empty?
    ProtocolBuffers::Compiler.compile_and_load(deps.map do |d|
      File.join(self::TMP_DIR, d)
    end, :include_dirs => [self::TMP_DIR])
  end
end

.fetch_and_save_dependencies(kode, url) ⇒ Object

:nodoc



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/betterific/protobuf_client.rb', line 36

def fetch_and_save_dependencies(kode, url) #:nodoc
  kode.scan(/import\s+'([^']+)';/).map do |imp|
    imp = imp.first
    imp_url = [url.split(/\//)[0..-2], imp].flatten.join('/')
    uri = URI(imp_url)
    if LAST_REFRESH[uri].nil? || (LAST_REFRESH[uri] < Time.now - PROTO_TTL_SECONDS)
      PROTO_SCHEMA_CACHE[uri] = get_http(URI(imp_url))
      File.open(File.join(self::TMP_DIR, imp), 'w') do |f|
        f.write(PROTO_SCHEMA_CACHE[uri].body)
      end
      LAST_REFRESH[uri] = Time.now
    end
    fetch_and_save_dependencies(PROTO_SCHEMA_CACHE[uri].body, url) + [imp]
  end.flatten.uniq
end

.get_namespaced_class(klass_string, o = nil) ⇒ Object

:nodoc



52
53
54
55
56
57
58
59
60
61
# File 'lib/betterific/protobuf_client.rb', line 52

def get_namespaced_class(klass_string, o=nil) #:nodoc
  return o if klass_string == nil
  unless klass_string.is_a?(Array)
    klass_string = klass_string.split(/::/)
  end
  o ||= Kernel
  o = o.const_get(klass_string.first)
  return o if klass_string.size == 1
  get_namespaced_class(klass_string[1..-1], o)
end

.get_protobuf(url, opts = {}, url_params = {}) ⇒ Object

:nodoc



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/betterific/protobuf_client.rb', line 63

def get_protobuf(url, opts={}, url_params={}) #:nodoc
  url = add_page_params(url, page_params_from_opts(opts))
  proto_url = if url =~ /\?/
    url.gsub(/\?/, '.protobuf?')
  else
    "#{url}.protobuf"
  end
  uri = URI(proto_url)
  unless url_params.empty?
    uri.query = URI.encode_www_form(url_params)
  end
  res = get_http(uri)
  schema_uri = URI(res.header['X-Protobuf-Schema'])
  if PROTO_SCHEMA_CACHE[schema_uri].nil? || LAST_REFRESH[schema_uri] < Time.now - PROTO_TTL_SECONDS
    PROTO_SCHEMA_CACHE[schema_uri] = get_http(schema_uri)
    LAST_REFRESH[schema_uri] = Time.now
  end
  proto_name = schema_uri.to_s.split(/\//).last
  compile_and_load_string(PROTO_SCHEMA_CACHE[schema_uri].body, schema_uri.to_s)
  proto_klass = get_namespaced_class("#{self::PROTO_PACKAGE_NAME}::#{proto_name.gsub(/\.proto$/, '').camelize}")
  proto_klass.parse(res.body)
end

.search(opts = {}) ⇒ Object

Search for betterifs, tags, and users.

Parameters

  • opts - => (all|betterifs|tags|users) specifies the type of object(s) to return.

    => <query> specifies the search query.



146
147
148
149
150
151
152
153
154
155
# File 'lib/betterific/protobuf_client.rb', line 146

def self.search(opts={})
  raise "No namespace given." if opts[:namespace].nil?
  raise "No q given." if opts[:q].nil?
  raise "q is blank." if opts[:q].blank?
  if [:betterifs, 'betterifs', :tags, 'tags', :users, 'users', :all, 'all'].include?(opts[:namespace])
    return get_protobuf("#{SEARCH_BASE_URL}/#{opts[:namespace]}?q=#{opts[:q]}")
  else
    raise "Invalid namespace: #{opts[:namespace]}"
  end
end

.tags(opts = {}) ⇒ Object

Get a list of tags.

Parameters

  • opts - => [id0, id1, …, idx] specifies the ids of the tag(s) to return.



116
117
118
119
120
121
122
# File 'lib/betterific/protobuf_client.rb', line 116

def self.tags(opts={})
  if opts[:ids]
    return get_protobuf("#{TAGS_BASE_URL}?tags[ids]=#{Array(opts[:ids]).map(&:to_s).join(',')}")
  else
    raise "No ids given."
  end
end

.users(opts = {}) ⇒ Object

Get a list of users.

Parameters

  • opts - => [id0, id1, …, idx] specifies the ids of the user(s) to return.



130
131
132
133
134
135
136
# File 'lib/betterific/protobuf_client.rb', line 130

def self.users(opts={})
  if opts[:ids]
    return get_protobuf("#{USERS_BASE_URL}?users[ids]=#{Array(opts[:ids]).map(&:to_s).join(',')}")
  else
    raise "No ids given."
  end
end