betterific 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ *.swp
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in betterific.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Brad Cater
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # Betterific
2
+
3
+ This gem makes it easy to access the Betterific API to explore betterifs, tags,
4
+ and users.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'betterific'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install betterific
19
+
20
+ ## Usage
21
+
22
+ To get started quickly, you should use Betterific::Client, which uses
23
+ Betterific::JsonClient in the absence of the
24
+ [ruby-protocol-buffers](https://github.com/codekitchen/ruby-protocol-buffers)
25
+ gem. This will use JSON as the data format and requires no extra gems besides
26
+ the [json](http://flori.github.io/json/) gem, which is likely already installed
27
+ on your machine.
28
+
29
+ Betterific::JsonClient wraps the JSON response using
30
+ [Hashie](https://github.com/intridea/hashie), so you may access the data using
31
+ JSON object notation or via method calls. For example,
32
+
33
+ Betterific::JsonClient.betterifs(:id => [224])['total_results']
34
+
35
+ is equivalent to
36
+
37
+ Betterific::JsonClient.betterifs(:id => [224]).total_results
38
+
39
+ However, it is recommended that you use the latter notation since it is
40
+ compatible with Betterific::ProtobufClient, whereas the JSON object notation is
41
+ not.
42
+
43
+ ### Betterifs
44
+
45
+ You can see the most popular betterifs of the last week using
46
+
47
+ Betterific::Client.betterifs(:most_popular)
48
+
49
+ A similar call can be used to see the most recent betterifs
50
+
51
+ Betterific::Client.betterifs(:most_recent)
52
+
53
+ If you already know the id(s) of the betterif(s) that you would like to see,
54
+ you can use
55
+
56
+ Betterific::Client.betterifs(:ids => [id0, id1, ...])
57
+
58
+ ### Tags and Users
59
+
60
+ You can see a list of tags or users by id using
61
+
62
+ Betterific::Client.tags(:ids => [id0, id1, ...])
63
+
64
+ and
65
+
66
+ Betterific::Client.users(:ids => [id0, id1, ...])
67
+
68
+ ### Search
69
+
70
+ You can search for betterifs, tags, users, or all of these using
71
+
72
+ Betterific::Client.search(:namespace => :all, :q => 'my query')
73
+
74
+ Changing the _:namespace_ parameter will change the type of data returned.
75
+
76
+ ### Pagination
77
+
78
+ All client methods take pagination params _:page_ and *:per_page*. In the case
79
+ of most popular and most recent betterifs, the filter must be changed to a Hash
80
+ parameter, like so
81
+
82
+ Betterific::Client.betterifs(:filter => :most_popular, :page => 2, :per_page => 10)
83
+
84
+ and
85
+
86
+ Betterific::Client.betterifs(:filter => :most_recent, :page => 2, :per_page => 10)
87
+
88
+ ### Using Protocol Buffers
89
+
90
+ If you have
91
+ [ruby-protocol-buffers](https://github.com/codekitchen/ruby-protocol-buffers)
92
+ installed, Betterific::Client will use Betterific::ProtobufClient in place of
93
+ Betterific::JsonClient. This will greatly improve performance, as
94
+ [Protocol Buffers](https://developers.google.com/protocol-buffers/) are highly
95
+ optimized.
96
+
97
+ The Betterific::ProtobufClient responds to the same methods as the
98
+ Betterific::JsonClient, so it's easy to switch between implementations at will.
99
+ For example,
100
+
101
+ Betterific::JsonClient.users(:id => [2])
102
+
103
+ and
104
+
105
+ Betterific::ProtobufClient.users(:id => [2])
106
+
107
+ return the same data as
108
+
109
+ Betterific::Client.users(:id => [2])
110
+
111
+ ## Contributing
112
+
113
+ 1. Fork it
114
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
115
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
116
+ 4. Push to the branch (`git push origin my-new-feature`)
117
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new('spec')
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/betterific/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Brad Cater"]
6
+ gem.email = ["bradcater@gmail.com"]
7
+ gem.description = %q{This gem is a Ruby interface to the Betterific API.}
8
+ gem.summary = %q{This gem is a Ruby interface to the Betterific API. It provides support via Protocol Buffers if the ruby-protocol-buffers gem is installed; otherwise, it uses JSON.}
9
+ gem.homepage = "https://github.com/bradcater/betterific"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "betterific"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Betterific::VERSION
17
+
18
+ gem.add_dependency 'hashie', '~> 2.0.5'
19
+ gem.add_dependency 'json', '~> 1.8.0'
20
+
21
+ gem.add_development_dependency 'ruby-protocol-buffers', '~> 2.4.0'
22
+ gem.add_development_dependency 'rspec', '~> 2.13.0'
23
+ end
@@ -0,0 +1,24 @@
1
+ module Betterific
2
+ module Client
3
+ # Delegate all methods to a client implementation if that client
4
+ # implementation supports the method. Use ProtobufClient if it's
5
+ # available; otherwise, use JsonClient.
6
+ #
7
+ CLIENT = if defined?(Betterific::ProtobufClient)
8
+ Betterific::ProtobufClient
9
+ else
10
+ Betterific::JsonClient
11
+ end
12
+
13
+ def self.respond_to?(method) #:nodoc:
14
+ return true if CLIENT.respond_to?(method)
15
+ super
16
+ end
17
+ def self.method_missing(method, *args, &block) #:nodoc:
18
+ if CLIENT.respond_to?(method)
19
+ return CLIENT.send(method, *args, &block)
20
+ end
21
+ super
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ module Betterific
2
+ module ClientConstants
3
+ # The base URL for the Betterific API.
4
+ BASE_URL = 'http://betterific.com/api'.freeze
5
+
6
+ # The base URL to GET betterifs.
7
+ BETTERIFS_BASE_URL = "#{BASE_URL}/betterifs".freeze
8
+ # The base URL to GET tags.
9
+ TAGS_BASE_URL = "#{BASE_URL}/tags".freeze
10
+ # The base URL to GET users.
11
+ USERS_BASE_URL = "#{BASE_URL}/users".freeze
12
+
13
+ # The base URL to GET search results.
14
+ SEARCH_BASE_URL = "#{BASE_URL}/search".freeze
15
+
16
+ # The package in which protocol buffer schemas are defined.
17
+ PROTO_PACKAGE_NAME = 'BetterIf'.freeze
18
+
19
+ # The directory in which to store temporary files.
20
+ TMP_DIR = File.expand_path(File.join('.', 'tmp'))
21
+ end
22
+ end
@@ -0,0 +1,45 @@
1
+ require 'net/http'
2
+
3
+ module Betterific
4
+ module ClientHelpers
5
+ def get_http(uri, opts={}) #:nodoc:
6
+ res = Net::HTTP.get_response(uri)
7
+ unless res.is_a?(Net::HTTPSuccess)
8
+ raise "Could not connect to #{uri}"
9
+ end
10
+ res
11
+ end; private :get_http
12
+
13
+ def add_page_params(url, opts={}) #:nodoc:
14
+ to_add = []
15
+ if opts[:page]
16
+ unless valid_page_param?(opts[:page])
17
+ raise "Invalid page: #{opts[:page]}"
18
+ end
19
+ to_add << "page=#{opts[:page]}"
20
+ end
21
+ if opts[:per_page]
22
+ unless valid_page_param?(opts[:per_page])
23
+ raise "Invalid per_page: #{opts[:per_page]}"
24
+ end
25
+ to_add << "per_page=#{opts[:per_page]}"
26
+ end
27
+ if to_add.size > 0
28
+ url = "#{url}#{url =~ /\?/ ? '&' : '?'}#{to_add.join('&')}"
29
+ end
30
+ url
31
+ end; private :add_page_params
32
+
33
+ def page_params_from_opts(opts) #:nodoc:
34
+ return {} unless opts.is_a?(Hash)
35
+ [:page, :per_page].inject({}) do |hsh, k|
36
+ hsh[k] = opts[k]
37
+ hsh
38
+ end
39
+ end; private :page_params_from_opts
40
+
41
+ def valid_page_param?(p) #:nodoc:
42
+ p.is_a?(Fixnum) && p > 0 && p.to_i == p
43
+ end; private :valid_page_param?
44
+ end
45
+ end
@@ -0,0 +1,89 @@
1
+ require 'hashie'
2
+ require 'json'
3
+
4
+ module Betterific
5
+ module JsonClient
6
+ include ::Betterific::ClientConstants
7
+ class << self
8
+ include ::Betterific::ClientHelpers
9
+ def get_json(url, opts={}, url_params={}) #:nodoc:
10
+ url = add_page_params(url, page_params_from_opts(opts))
11
+ uri = URI(url)
12
+ unless url_params.empty?
13
+ uri.query = URI.encode_www_form(url_params)
14
+ end
15
+ Hashie::Mash.new(JSON.parse(get_http(uri).body))
16
+ end; private :get_json
17
+ end
18
+
19
+ # Get a list of betterifs.
20
+ #
21
+ # ==== Parameters
22
+ #
23
+ # * +opts+ - If most_popular, gets the most popular betterifs of the last
24
+ # week.
25
+ #
26
+ # If most_recent, gets the most recent betterifs.
27
+ #
28
+ # {:ids => [id0, id1, ..., idx]} specifies the ids of the betterif(s) to
29
+ # return.
30
+ def self.betterifs(opts={})
31
+ if [:most_popular, 'most_popular'].include?(opts) || (opts.is_a?(Hash) && [:most_popular, 'most_popular'].include?(opts[:filter]))
32
+ return get_json("#{BETTERIFS_BASE_URL}/most-popular")
33
+ elsif [:most_recent, 'most_recent'].include?(opts) || (opts.is_a?(Hash) && [:most_recent, 'most_recent'].include?(opts[:filter]))
34
+ return get_json("#{BETTERIFS_BASE_URL}/most-recent")
35
+ elsif opts[:ids]
36
+ return get_json("#{BETTERIFS_BASE_URL}?betterifs[ids]=#{Array(opts[:ids]).map(&:to_s).join(',')}")
37
+ else
38
+ raise "No filter and no ids given."
39
+ end
40
+ end
41
+
42
+ # Get a list of tags.
43
+ #
44
+ # ==== Parameters
45
+ #
46
+ # * +opts+ - {:ids => [id0, id1, ..., idx]} specifies the ids of the
47
+ # tag(s) to return.
48
+ def self.tags(opts={})
49
+ if opts[:ids]
50
+ return get_json("#{TAGS_BASE_URL}?tags[ids]=#{Array(opts[:ids]).map(&:to_s).join(',')}")
51
+ else
52
+ raise "No ids given."
53
+ end
54
+ end
55
+
56
+ # Get a list of users.
57
+ #
58
+ # ==== Parameters
59
+ #
60
+ # * +opts+ - {:ids => [id0, id1, ..., idx]} specifies the ids of the
61
+ # user(s) to return.
62
+ def self.users(opts={})
63
+ if opts[:ids]
64
+ return get_json("#{USERS_BASE_URL}?users[ids]=#{Array(opts[:ids]).map(&:to_s).join(',')}")
65
+ else
66
+ raise "No ids given."
67
+ end
68
+ end
69
+
70
+ # Search for betterifs, tags, and users.
71
+ #
72
+ # ==== Parameters
73
+ #
74
+ # * +opts+ - {:namespace => (all|betterifs|tags|users)} specifies the type
75
+ # of object(s) to return.
76
+ #
77
+ # {:q => <query>} specifies the search query.
78
+ def self.search(opts={})
79
+ raise "No namespace given." if opts[:namespace].nil?
80
+ raise "No q given." if opts[:q].nil?
81
+ raise "q is blank." if opts[:q].blank?
82
+ if [:betterifs, 'betterifs', :tags, 'tags', :users, 'users', :all, 'all'].include?(opts[:namespace])
83
+ return get_json("#{SEARCH_BASE_URL}/#{opts[:namespace]}?q=#{opts[:q]}")
84
+ else
85
+ raise "Invalid namespace: #{opts[:namespace]}"
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,157 @@
1
+ require 'protocol_buffers'
2
+ require 'protocol_buffers/compiler'
3
+
4
+ module Betterific
5
+ module ProtobufClient
6
+ include ::Betterific::ClientConstants
7
+ class << self
8
+ include ::Betterific::ClientHelpers
9
+ # Cache of the last time a schema was refreshed by name.
10
+ LAST_REFRESH = {}
11
+ # Cache of schemas by URI.
12
+ PROTO_SCHEMA_CACHE = {}
13
+ # How many seconds to keep a schema before refreshing.
14
+ PROTO_TTL_SECONDS = 60
15
+ def compile_and_load_string(kode, url) #:nodoc
16
+ unless Dir.exists?(self::TMP_DIR)
17
+ Dir.mkdir(self::TMP_DIR, 0700)
18
+ end
19
+ deps = fetch_and_save_dependencies(kode, url)
20
+ fname = url.split(/\//)[-1]
21
+ File.open(File.join(self::TMP_DIR, fname), 'w') do |f|
22
+ f.write(kode)
23
+ end
24
+ deps << fname
25
+ deps = deps.reject do |d|
26
+ Kernel.const_defined?(self::PROTO_PACKAGE_NAME.to_sym) && Kernel.const_get(self::PROTO_PACKAGE_NAME.to_sym)
27
+ .const_defined?(d.gsub(/\.proto$/, '').camelize.to_sym)
28
+ end
29
+ unless deps.empty?
30
+ ProtocolBuffers::Compiler.compile_and_load(deps.map do |d|
31
+ File.join(self::TMP_DIR, d)
32
+ end, :include_dirs => [self::TMP_DIR])
33
+ end
34
+ end; private :compile_and_load_string
35
+
36
+ def fetch_and_save_dependencies(kode, url) #:nodoc
37
+ kode.scan(/import\s+'([^']+)';/).map do |imp|
38
+ imp = imp.first
39
+ imp_url = [url.split(/\//)[0..-2], imp].flatten.join('/')
40
+ uri = URI(imp_url)
41
+ if LAST_REFRESH[uri].nil? || (LAST_REFRESH[uri] < Time.now - PROTO_TTL_SECONDS)
42
+ PROTO_SCHEMA_CACHE[uri] = get_http(URI(imp_url))
43
+ File.open(File.join(self::TMP_DIR, imp), 'w') do |f|
44
+ f.write(PROTO_SCHEMA_CACHE[uri].body)
45
+ end
46
+ LAST_REFRESH[uri] = Time.now
47
+ end
48
+ fetch_and_save_dependencies(PROTO_SCHEMA_CACHE[uri].body, url) + [imp]
49
+ end.flatten.uniq
50
+ end; private :fetch_and_save_dependencies
51
+
52
+ def get_namespaced_class(klass_string, o=nil) #:nodoc
53
+ return o if klass_string == nil
54
+ unless klass_string.is_a?(Array)
55
+ klass_string = klass_string.split(/::/)
56
+ end
57
+ o ||= Kernel
58
+ o = o.const_get(klass_string.first)
59
+ return o if klass_string.size == 1
60
+ get_namespaced_class(klass_string[1..-1], o)
61
+ end; private :get_namespaced_class
62
+
63
+ def get_protobuf(url, opts={}, url_params={}) #:nodoc
64
+ url = add_page_params(url, page_params_from_opts(opts))
65
+ proto_url = if url =~ /\?/
66
+ url.gsub(/\?/, '.protobuf?')
67
+ else
68
+ "#{url}.protobuf"
69
+ end
70
+ uri = URI(proto_url)
71
+ unless url_params.empty?
72
+ uri.query = URI.encode_www_form(url_params)
73
+ end
74
+ res = get_http(uri)
75
+ schema_uri = URI(res.header['X-Protobuf-Schema'])
76
+ if PROTO_SCHEMA_CACHE[schema_uri].nil? || LAST_REFRESH[schema_uri] < Time.now - PROTO_TTL_SECONDS
77
+ PROTO_SCHEMA_CACHE[schema_uri] = get_http(schema_uri)
78
+ LAST_REFRESH[schema_uri] = Time.now
79
+ end
80
+ proto_name = schema_uri.to_s.split(/\//).last
81
+ compile_and_load_string(PROTO_SCHEMA_CACHE[schema_uri].body, schema_uri.to_s)
82
+ proto_klass = get_namespaced_class("#{self::PROTO_PACKAGE_NAME}::#{proto_name.gsub(/\.proto$/, '').camelize}")
83
+ proto_klass.parse(res.body)
84
+ end; private :get_protobuf
85
+ end
86
+
87
+ # Get a list of betterifs.
88
+ #
89
+ # ==== Parameters
90
+ #
91
+ # * +opts+ - If most_popular, gets the most popular betterifs of the last
92
+ # week.
93
+ #
94
+ # If most_recent, gets the most recent betterifs.
95
+ #
96
+ # {:ids => [id0, id1, ..., idx]} specifies the ids of the betterif(s) to
97
+ # return.
98
+ def self.betterifs(opts={})
99
+ if [:most_popular, 'most_popular'].include?(opts) || (opts.is_a?(Hash) && [:most_popular, 'most_popular'].include?(opts[:filter]))
100
+ return get_protobuf("#{BETTERIFS_BASE_URL}/most-popular")
101
+ elsif [:most_recent, 'most_recent'].include?(opts) || (opts.is_a?(Hash) && [:most_recent, 'most_recent'].include?(opts[:filter]))
102
+ return get_protobuf("#{BETTERIFS_BASE_URL}/most-recent")
103
+ elsif opts[:ids]
104
+ return get_protobuf("#{BETTERIFS_BASE_URL}?betterifs[ids]=#{Array(opts[:ids]).map(&:to_s).join(',')}")
105
+ else
106
+ raise "No filter and no ids given."
107
+ end
108
+ end
109
+
110
+ # Get a list of tags.
111
+ #
112
+ # ==== Parameters
113
+ #
114
+ # * +opts+ - {:ids => [id0, id1, ..., idx]} specifies the ids of the
115
+ # tag(s) to return.
116
+ def self.tags(opts={})
117
+ if opts[:ids]
118
+ return get_protobuf("#{TAGS_BASE_URL}?tags[ids]=#{Array(opts[:ids]).map(&:to_s).join(',')}")
119
+ else
120
+ raise "No ids given."
121
+ end
122
+ end
123
+
124
+ # Get a list of users.
125
+ #
126
+ # ==== Parameters
127
+ #
128
+ # * +opts+ - {:ids => [id0, id1, ..., idx]} specifies the ids of the
129
+ # user(s) to return.
130
+ def self.users(opts={})
131
+ if opts[:ids]
132
+ return get_protobuf("#{USERS_BASE_URL}?users[ids]=#{Array(opts[:ids]).map(&:to_s).join(',')}")
133
+ else
134
+ raise "No ids given."
135
+ end
136
+ end
137
+
138
+ # Search for betterifs, tags, and users.
139
+ #
140
+ # ==== Parameters
141
+ #
142
+ # * +opts+ - {:namespace => (all|betterifs|tags|users)} specifies the type
143
+ # of object(s) to return.
144
+ #
145
+ # {:q => <query>} specifies the search query.
146
+ def self.search(opts={})
147
+ raise "No namespace given." if opts[:namespace].nil?
148
+ raise "No q given." if opts[:q].nil?
149
+ raise "q is blank." if opts[:q].blank?
150
+ if [:betterifs, 'betterifs', :tags, 'tags', :users, 'users', :all, 'all'].include?(opts[:namespace])
151
+ return get_protobuf("#{SEARCH_BASE_URL}/#{opts[:namespace]}?q=#{opts[:q]}")
152
+ else
153
+ raise "Invalid namespace: #{opts[:namespace]}"
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,46 @@
1
+ class Object
2
+ unless nil.respond_to?(:present?)
3
+ # Return true if self is not nil, false otherwise.
4
+ #
5
+ # This is defined only if it is not yet defined.
6
+ #
7
+ def present?
8
+ !self.nil?
9
+ end
10
+ end
11
+ end
12
+
13
+ class String
14
+
15
+ unless ''.respond_to?(:blank?)
16
+ # Return true if self has length 0 or is only whitespace, false otherwise.
17
+ #
18
+ # This is defined only if it is not yet defined.
19
+ #
20
+ def blank?
21
+ self.strip.size == 0
22
+ end
23
+ end
24
+
25
+ #Adapted from
26
+ #https://www.ruby-forum.com/topic/4411006
27
+ unless ''.respond_to?(:camelize)
28
+ # Return a camel-case version of self, in contrast to underscore.
29
+ #
30
+ # This is defined only if it is not yet defined.
31
+ #
32
+ def camelize
33
+ self.split('_').each(&:capitalize!).join
34
+ end
35
+ end
36
+ unless ''.respond_to?(:underscore)
37
+ # Return an underscore version of self, in contrast to camel-case.
38
+ #
39
+ # This is defined only if it is not yet defined.
40
+ #
41
+ def underscore
42
+ self.scan(/[A-Z][a-z]*/).join('_').downcase
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1,3 @@
1
+ module Betterific
2
+ VERSION = "0.0.1" #:nodoc:
3
+ end
data/lib/betterific.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'betterific/client_constants'
2
+ require 'betterific/client_helpers'
3
+ require 'betterific/ruby_extensions'
4
+ require 'betterific/version'
5
+
6
+ require 'betterific/json_client'
7
+ if Gem::Specification.find_all_by_name('ruby-protocol-buffers').any?
8
+ require 'betterific/protobuf_client'
9
+ else
10
+ puts 'Betterific: Install the ruby-protocol-buffers gem to use Betterific::ProtobufClient.'
11
+ end
12
+
13
+ require 'betterific/client'
14
+
15
+ module Betterific
16
+ # See a human-readable form of this gem's current version.
17
+ #
18
+ def self.version_string
19
+ "Betterific version #{Betterific::VERSION}"
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Betterific do
4
+ it 'should return correct version string' do
5
+ Betterific.version_string.should == "Betterific version #{Betterific::VERSION}"
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ require 'spec_helper'
2
+
3
+ client_test(Betterific::Client)
@@ -0,0 +1,3 @@
1
+ require 'spec_helper'
2
+
3
+ client_test(Betterific::JsonClient)
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ if defined?(Betterific::ProtobufClient)
4
+ client_test(Betterific::ProtobufClient)
5
+ end
@@ -0,0 +1,147 @@
1
+ require 'betterific'
2
+
3
+ BETTERIFIC_TAG_ID = 400937 #:nodoc
4
+ BETTERIF_ID = 224 #:nodoc
5
+ USER_ID = 2 #:nodoc
6
+
7
+ SEARCH_KINDS = %w{betterifs tags users}.freeze #:nodoc
8
+
9
+ def ensure_valid_api_response(resp, client_modjule, opts={})
10
+ if opts[:big]
11
+ resp.total_results.should > 10
12
+ else
13
+ resp.total_results.should >= (opts[:allow_empty] ? 0 : 1)
14
+ end
15
+ if opts[:big]
16
+ resp.num_results.should == 10
17
+ else
18
+ resp.num_results.should >= (opts[:allow_empty] ? 0 : 1)
19
+ end
20
+ if opts[:betterifs]
21
+ if opts[:big]
22
+ resp.betterifs.size.should == 10
23
+ else
24
+ resp.betterifs.size.should >= (opts[:allow_empty] ? 0 : 1)
25
+ end
26
+ unless opts[:allow_empty]
27
+ if client_modjule == Betterific::JsonClient
28
+ resp.betterifs.first.tags.is_a?(Array).should == true
29
+ elsif client_modjule == Betterific::ProtobufClient
30
+ resp.betterifs.first.tags.is_a?(ProtocolBuffers::RepeatedField).should == true
31
+ else
32
+ raise "Invalid client_modjule #{client_modjule}"
33
+ end
34
+ if resp.betterifs.first.tags.size > 0
35
+ if client_modjule == Betterific::ProtobufClient
36
+ resp.betterifs.first.tags.first.is_a?(BetterIf::Tag).should == true
37
+ end
38
+ end
39
+ if client_modjule == Betterific::ProtobufClient
40
+ resp.betterifs.first.user.is_a?(BetterIf::User).should == true
41
+ end
42
+ end
43
+ end
44
+ if opts[:tags]
45
+ if opts[:big]
46
+ resp.tags.size.should == 10
47
+ else
48
+ resp.tags.size.should >= (opts[:allow_empty] ? 0 : 1)
49
+ end
50
+ if client_modjule == Betterific::JsonClient
51
+ resp.tags.is_a?(Array).should == true
52
+ elsif client_modjule == Betterific::ProtobufClient
53
+ resp.tags.is_a?(ProtocolBuffers::RepeatedField).should == true
54
+ else
55
+ raise "Invalid client_modjule #{client_modjule}"
56
+ end
57
+ if client_modjule == Betterific::ProtobufClient && resp.tags.size > 0
58
+ resp.tags.first.is_a?(BetterIf::Tag).should == true
59
+ end
60
+ end
61
+ if opts[:users]
62
+ if opts[:big]
63
+ resp.users.size.should == 10
64
+ else
65
+ resp.users.size.should >= (opts[:allow_empty] ? 0 : 1)
66
+ end
67
+ if client_modjule == Betterific::JsonClient
68
+ resp.users.is_a?(Array).should == true
69
+ elsif client_modjule == Betterific::ProtobufClient
70
+ resp.users.is_a?(ProtocolBuffers::RepeatedField).should == true
71
+ else
72
+ raise "Invalid client_modjule #{client_modjule}"
73
+ end
74
+ if client_modjule == Betterific::ProtobufClient && resp.users.size > 0
75
+ resp.users.first.is_a?(BetterIf::User).should == true
76
+ end
77
+ end
78
+ end
79
+
80
+ def client_test(modjule)
81
+ describe modjule do
82
+ [['without page params', {}],
83
+ ['with page params', {:page => 2, :per_page => 1}]].each do |(page_params_lbl, page_params)|
84
+ describe page_params_lbl do
85
+ [:most_popular, :most_recent].each do |filter|
86
+ it "should load #{filter} betterifs" do
87
+ resp = modjule.betterifs(page_params.merge(:filter => filter))
88
+ ensure_valid_api_response(resp, :betterifs => true, :big => page_params.empty?)
89
+ end
90
+ end
91
+ it "should load betterifs via ids" do
92
+ resp = modjule.betterifs(page_params.merge(:ids => BETTERIF_ID))
93
+ ensure_valid_api_response(resp, :betterifs => true, :allow_empty => !page_params.empty?)
94
+ if page_params.empty?
95
+ resp.betterifs.first.id.should == BETTERIF_ID
96
+ end
97
+ end
98
+ it "should load tags via ids" do
99
+ resp = modjule.tags(page_params.merge(:ids => BETTERIFIC_TAG_ID))
100
+ ensure_valid_api_response(resp, :tags => true, :allow_empty => !page_params.empty?)
101
+ if page_params.empty?
102
+ resp.tags.first.id.should == BETTERIFIC_TAG_ID
103
+ end
104
+ end
105
+ it "should load users via ids" do
106
+ resp = modjule.users(page_params.merge(:ids => USER_ID))
107
+ ensure_valid_api_response(resp, :users => true, :allow_empty => !page_params.empty?)
108
+ if page_params.empty?
109
+ resp.users.first.id.should == USER_ID
110
+ end
111
+ end
112
+
113
+ SEARCH_KINDS.each do |kind|
114
+ it "should load search for #{kind}" do
115
+ q = random_query
116
+ resp = modjule.search(page_params.merge(:namespace => kind, :q => q))
117
+ resp.q.should == q
118
+ ensure_valid_api_response(resp.send(kind), kind.to_sym => true, :allow_empty => true)
119
+ if modjule == Betterific::JsonClient
120
+ SEARCH_KINDS.each do |other_kind|
121
+ next if kind == other_kind
122
+ resp.send(other_kind).present?.should == false
123
+ end
124
+ end
125
+ end
126
+ end
127
+ it "should load search for all" do
128
+ q = random_query
129
+ resp = modjule.search(page_params.merge(:namespace => :all, :q => q))
130
+ resp.q.should == q
131
+ SEARCH_KINDS.each do |kind|
132
+ ensure_valid_api_response(resp.send(kind), kind.to_sym => true, :allow_empty => true)
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ def random_query
141
+ 'abcdefghijklmnopqrstuvwxyz'.split(//).sample
142
+ end
143
+
144
+ RSpec.configure do |config|
145
+ config.color_enabled = true
146
+ config.formatter = 'documentation'
147
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: betterific
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Brad Cater
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: hashie
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.0.5
22
+ prerelease: false
23
+ type: :runtime
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 2.0.5
30
+ - !ruby/object:Gem::Dependency
31
+ name: json
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.8.0
38
+ prerelease: false
39
+ type: :runtime
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.8.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: ruby-protocol-buffers
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 2.4.0
54
+ prerelease: false
55
+ type: :development
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 2.4.0
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 2.13.0
70
+ prerelease: false
71
+ type: :development
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 2.13.0
78
+ description: This gem is a Ruby interface to the Betterific API.
79
+ email:
80
+ - bradcater@gmail.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - Gemfile
87
+ - LICENSE
88
+ - README.md
89
+ - Rakefile
90
+ - betterific.gemspec
91
+ - lib/betterific.rb
92
+ - lib/betterific/client.rb
93
+ - lib/betterific/client_constants.rb
94
+ - lib/betterific/client_helpers.rb
95
+ - lib/betterific/json_client.rb
96
+ - lib/betterific/protobuf_client.rb
97
+ - lib/betterific/ruby_extensions.rb
98
+ - lib/betterific/version.rb
99
+ - spec/betterific_spec.rb
100
+ - spec/client_spec.rb
101
+ - spec/json_client_spec.rb
102
+ - spec/protobuf_client_spec.rb
103
+ - spec/spec_helper.rb
104
+ homepage: https://github.com/bradcater/betterific
105
+ licenses: []
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ! '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ! '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 1.8.25
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: This gem is a Ruby interface to the Betterific API. It provides support via
128
+ Protocol Buffers if the ruby-protocol-buffers gem is installed; otherwise, it uses
129
+ JSON.
130
+ test_files:
131
+ - spec/betterific_spec.rb
132
+ - spec/client_spec.rb
133
+ - spec/json_client_spec.rb
134
+ - spec/protobuf_client_spec.rb
135
+ - spec/spec_helper.rb