betterific 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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