masheri 0.5.6 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.yardoc/checksums +17 -0
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/.yardoc/proxy_types +0 -0
- data/Gemfile +22 -0
- data/Gemfile.devtools +55 -0
- data/Gemfile.lock +255 -0
- data/Rakefile +9 -0
- data/VERSION +1 -0
- data/config/devtools.yml +2 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/mutant.yml +3 -0
- data/config/reek.yml +103 -0
- data/config/rubocop.yml +58 -0
- data/config/yardstick.yml +2 -0
- data/lib/masheri.rb +2 -1
- data/lib/masheri/key.rb +1 -1
- data/lib/masheri/member.rb +1 -1
- data/lib/masheri/{rest_client → rpc_client}/base.rb +2 -2
- data/lib/masheri/service.rb +1 -1
- data/masheri.gemspec +26 -0
- data/spec/fixtures/config.no_host.yml +4 -0
- data/spec/fixtures/config.no_key.yml +4 -0
- data/spec/fixtures/config.no_secret.yml +4 -0
- data/spec/fixtures/config.no_site_id.yml +4 -0
- data/spec/fixtures/config.yml +5 -0
- data/spec/fixtures/services.json +3 -0
- data/spec/masheri/config_spec.rb +38 -0
- data/spec/masheri/member_spec.rb +47 -0
- data/spec/masheri/query_builder_spec.rb +13 -0
- data/spec/masheri/rest_client_spec.rb +47 -0
- data/spec/masheri/rpc_client_spec.rb +29 -0
- data/spec/masheri/service_spec.rb +101 -0
- data/spec/masheri_spec.rb +5 -0
- data/spec/spec_helper.rb +49 -0
- data/tasks/mashery.thor +200 -0
- metadata +40 -102
data/config/rubocop.yml
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
AllCops:
|
2
|
+
Includes:
|
3
|
+
- '**/*.rake'
|
4
|
+
- 'Gemfile'
|
5
|
+
- 'Gemfile.devtools'
|
6
|
+
Excludes:
|
7
|
+
- '**/vendor/**'
|
8
|
+
- '**/benchmarks/**'
|
9
|
+
|
10
|
+
# Avoid parameter lists longer than five parameters.
|
11
|
+
ParameterLists:
|
12
|
+
Max: 3
|
13
|
+
CountKeywordArgs: true
|
14
|
+
|
15
|
+
# Avoid more than `Max` levels of nesting.
|
16
|
+
BlockNesting:
|
17
|
+
Max: 3
|
18
|
+
|
19
|
+
# Align with the style guide.
|
20
|
+
CollectionMethods:
|
21
|
+
PreferredMethods:
|
22
|
+
collect: 'map'
|
23
|
+
inject: 'reduce'
|
24
|
+
find: 'detect'
|
25
|
+
find_all: 'select'
|
26
|
+
|
27
|
+
# Do not force public/protected/private keyword to be indented at the same
|
28
|
+
# level as the def keyword. My personal preference is to outdent these keywords
|
29
|
+
# because I think when scanning code it makes it easier to identify the
|
30
|
+
# sections of code and visually separate them. When the keyword is at the same
|
31
|
+
# level I think it sort of blends in with the def keywords and makes it harder
|
32
|
+
# to scan the code and see where the sections are.
|
33
|
+
AccessControl:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
# Limit line length
|
37
|
+
LineLength:
|
38
|
+
Max: 79
|
39
|
+
|
40
|
+
# Disable documentation checking until a class needs to be documented once
|
41
|
+
Documentation:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
# Do not favor modifier if/unless usage when you have a single-line body
|
45
|
+
IfUnlessModifier:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
# Allow case equality operator (in limited use within the specs)
|
49
|
+
CaseEquality:
|
50
|
+
Enabled: false
|
51
|
+
|
52
|
+
# Constants do not always have to use SCREAMING_SNAKE_CASE
|
53
|
+
ConstantName:
|
54
|
+
Enabled: false
|
55
|
+
|
56
|
+
# Not all trivial readers/writers can be defined with attr_* methods
|
57
|
+
TrivialAccessors:
|
58
|
+
Enabled: false
|
data/lib/masheri.rb
CHANGED
@@ -9,12 +9,13 @@ require 'masheri/exceptions'
|
|
9
9
|
require 'masheri/config'
|
10
10
|
|
11
11
|
require 'masheri/rpc_client'
|
12
|
+
require 'masheri/rpc_client/base'
|
12
13
|
require 'masheri/rpc_client/response'
|
13
14
|
|
14
15
|
require 'masheri/rest_client'
|
15
16
|
require 'masheri/query_builder'
|
16
17
|
require 'masheri/rest_client/query'
|
17
|
-
|
18
|
+
|
18
19
|
|
19
20
|
require 'masheri/member'
|
20
21
|
require 'masheri/key'
|
data/lib/masheri/key.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Masheri
|
2
|
-
class Key <
|
2
|
+
class Key < RpcClient::Base
|
3
3
|
attr_accessor(:id, :created, :updated, :service_key, :apikey, :username, :status,
|
4
4
|
:rate_limit_ceiling, :qps_limit_ceiling, :rate_limit_exempt, :qps_limit_exempt,
|
5
5
|
:required_referer, :secret, :limits, :object_type)
|
data/lib/masheri/member.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Masheri
|
2
|
-
class Member <
|
2
|
+
class Member < RpcClient::Base
|
3
3
|
attr_accessor(:created, :updated, :username, :email, :display_name,
|
4
4
|
:uri, :blog, :im, :imsvc, :phone, :company, :address1, :address2,
|
5
5
|
:locality, :region, :postal_code, :country_code, :first_name, :last_name,
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Masheri
|
2
|
-
class
|
2
|
+
class RpcClient
|
3
3
|
class Base
|
4
4
|
def initialize(attributes)
|
5
5
|
attributes.each do |key, value|
|
@@ -44,7 +44,7 @@ module Masheri
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def self.object_type
|
47
|
-
self.name.underscore.pluralize
|
47
|
+
self.name.underscore.split('/').last.pluralize
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
data/lib/masheri/service.rb
CHANGED
data/masheri.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "masheri"
|
3
|
+
s.version = File.read("VERSION")
|
4
|
+
|
5
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
|
+
s.authors = ["Farley Knight"]
|
7
|
+
s.date = "2013-09-23"
|
8
|
+
s.email = "farleyknight@gmail.com"
|
9
|
+
s.extra_rdoc_files = [
|
10
|
+
"LICENSE.txt",
|
11
|
+
"README.md",
|
12
|
+
"README.textile"
|
13
|
+
]
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
|
17
|
+
s.homepage = "http://github.com/farleyknight/masheri"
|
18
|
+
s.licenses = ["MIT"]
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
s.rubygems_version = "1.8.25"
|
21
|
+
s.summary = "Rails gem for Mashery. Clean config and includes tests with decent test coverage"
|
22
|
+
|
23
|
+
s.add_dependency(%q<activesupport>, [">= 3.1.0"])
|
24
|
+
s.add_dependency(%q<rest-client>, [">= 0"])
|
25
|
+
s.add_dependency(%q<json>, [">= 0"])
|
26
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Masheri::Config do
|
4
|
+
it "should raise an error on lack of key" do
|
5
|
+
expect {
|
6
|
+
Masheri::Config.new("spec/fixtures/config.no_key.yml")
|
7
|
+
}.to raise_error(Masheri::ParamMissing, /key/)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should raise an error on lack of site_id" do
|
11
|
+
expect {
|
12
|
+
Masheri::Config.new("spec/fixtures/config.no_site_id.yml")
|
13
|
+
}.to raise_error(Masheri::ParamMissing, /site_id/)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should raise an error on lack of secret" do
|
17
|
+
expect {
|
18
|
+
Masheri::Config.new("spec/fixtures/config.no_secret.yml")
|
19
|
+
}.to raise_error(Masheri::ParamMissing, /secret/)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should raise an error on lack of host" do
|
23
|
+
expect {
|
24
|
+
Masheri::Config.new("spec/fixtures/config.no_host.yml")
|
25
|
+
}.to raise_error(Masheri::ParamMissing, /host/)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should have site_id, key, secret, host and signature as attributes" do
|
29
|
+
config = Masheri::Config.new("spec/fixtures/config.yml")
|
30
|
+
expect do
|
31
|
+
config.key
|
32
|
+
config.secret
|
33
|
+
config.signature
|
34
|
+
config.host
|
35
|
+
config.site_id
|
36
|
+
end.to_not raise_error
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Masheri::Member do
|
4
|
+
let(:url) { Masheri.rpc.url }
|
5
|
+
|
6
|
+
let(:items) {
|
7
|
+
[{"name" => "Name"}] * 10
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:params) {
|
11
|
+
{
|
12
|
+
'method' => "object.query",
|
13
|
+
'params' => [query],
|
14
|
+
'id' => 1
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:headers) {
|
19
|
+
{
|
20
|
+
"Content-Type" => "application/json",
|
21
|
+
"Accept" => "text/plain",
|
22
|
+
"Content-Length" => params.size
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
let(:json) {
|
27
|
+
{
|
28
|
+
"result" => {
|
29
|
+
"items" => items
|
30
|
+
}
|
31
|
+
}.to_json
|
32
|
+
}
|
33
|
+
|
34
|
+
|
35
|
+
context "with standard query" do
|
36
|
+
let(:query) {
|
37
|
+
"SELECT * FROM members ITEMS 100"
|
38
|
+
}
|
39
|
+
|
40
|
+
it "should grab all the members" do
|
41
|
+
::RestClient.should_receive(:post).with(url, params.to_json, headers).and_return(json)
|
42
|
+
objects = Masheri::Member.all
|
43
|
+
objects.length.should == 10
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Masheri::QueryBuilder do
|
4
|
+
it "should build a simple query" do
|
5
|
+
builder = Masheri::QueryBuilder.new
|
6
|
+
builder.from("members").to_s.should == "SELECT * FROM members"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should build a query with pagination" do
|
10
|
+
builder = Masheri::QueryBuilder.new
|
11
|
+
builder.from("members").page(25).items(100).to_s.should == "SELECT * FROM members PAGE 25 ITEMS 100"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Masheri::RestClient do
|
4
|
+
let(:service_key) do
|
5
|
+
"12345"
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:url) do
|
9
|
+
Masheri::RestClient::Query.new(query_params).url
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:query_params) do
|
13
|
+
{service_id: service_key}.merge(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
context "reasonable date range" do
|
18
|
+
let(:options) do
|
19
|
+
{
|
20
|
+
start_date: 1.day.ago,
|
21
|
+
end_date: 0.days.ago,
|
22
|
+
resource: "developer_activity"
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should request the service data, given a service key" do
|
27
|
+
::RestClient.should_receive(:get).with(url).and_return("whatever")
|
28
|
+
Masheri.activity("developer_activity", service_key, options).should == "whatever"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "invalid date range" do
|
33
|
+
let(:options) do
|
34
|
+
{
|
35
|
+
start_date: 8.day.ago,
|
36
|
+
end_date: 0.days.ago,
|
37
|
+
resource: "developer_activity"
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should raise an InvalidDateRange error" do
|
42
|
+
expect do
|
43
|
+
Masheri.activity("developer_activity", service_key, options)
|
44
|
+
end.to raise_error(Masheri::InvalidDateRange)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Masheri::RpcClient do
|
4
|
+
let(:query) {
|
5
|
+
"SELECT * FROM whatevers"
|
6
|
+
}
|
7
|
+
|
8
|
+
let(:params) {
|
9
|
+
{
|
10
|
+
'method' => "object.query",
|
11
|
+
'params' => [query],
|
12
|
+
'id' => 1
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
let(:headers) {
|
17
|
+
{
|
18
|
+
"Content-Type" => "application/json",
|
19
|
+
"Accept" => "text/plain",
|
20
|
+
"Content-Length" => params.size
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
it "should post to RpcClient with the proper arguments" do
|
25
|
+
::RestClient.should_receive(:post).with(Masheri.rpc.url, params.to_json, headers).and_return({hello: 'world'}.to_json)
|
26
|
+
Masheri.rpc.query(query)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Masheri::Service do
|
4
|
+
let(:url) { Masheri.rpc.url }
|
5
|
+
|
6
|
+
let(:items) {
|
7
|
+
[{"name" => "Name"}] * 10
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:params) {
|
11
|
+
{
|
12
|
+
'method' => "object.query",
|
13
|
+
'params' => [query],
|
14
|
+
'id' => 1
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:headers) {
|
19
|
+
{
|
20
|
+
"Content-Type" => "application/json",
|
21
|
+
"Accept" => "text/plain",
|
22
|
+
"Content-Length" => params.size
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
let(:json) {
|
27
|
+
{
|
28
|
+
"result" => {
|
29
|
+
"items" => items
|
30
|
+
}
|
31
|
+
}.to_json
|
32
|
+
}
|
33
|
+
|
34
|
+
context "with standard query" do
|
35
|
+
let(:query) { "SELECT * FROM services ITEMS 100" }
|
36
|
+
|
37
|
+
it "should grab all the services" do
|
38
|
+
::RestClient.should_receive(:post).with(url, params.to_json, headers).and_return(json)
|
39
|
+
objects = Masheri::Service.all
|
40
|
+
objects.length.should == 10
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "with pagination query" do
|
45
|
+
let(:query) { "SELECT * FROM services PAGE 3 ITEMS 100"}
|
46
|
+
|
47
|
+
it "should grab the 3rd page of services" do
|
48
|
+
::RestClient.should_receive(:post).with(url, params.to_json, headers).and_return(json)
|
49
|
+
objects = Masheri::Service.page(3).all
|
50
|
+
objects.length.should == 10
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "with auto-pagination via find_each" do
|
55
|
+
let(:total_pages) { 5 }
|
56
|
+
|
57
|
+
def query(page)
|
58
|
+
if page == 1
|
59
|
+
"SELECT * FROM services ITEMS 100"
|
60
|
+
else
|
61
|
+
"SELECT * FROM services PAGE #{page} ITEMS 100"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def params(page)
|
66
|
+
{
|
67
|
+
'method' => "object.query",
|
68
|
+
'params' => [query(page)],
|
69
|
+
'id' => 1
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def json(page)
|
74
|
+
{
|
75
|
+
"result" => {
|
76
|
+
"total_pages" => total_pages,
|
77
|
+
"current_page" => page,
|
78
|
+
"items" => items
|
79
|
+
}
|
80
|
+
}.to_json
|
81
|
+
end
|
82
|
+
|
83
|
+
def headers(page)
|
84
|
+
{
|
85
|
+
"Content-Type" => "application/json",
|
86
|
+
"Accept" => "text/plain",
|
87
|
+
"Content-Length" => params(page).size
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should invoke a new query for each page" do
|
92
|
+
(1..total_pages).each do |n|
|
93
|
+
::RestClient.should_receive(:post).with(url, params(n).to_json, headers(n)).and_return(json(n))
|
94
|
+
end
|
95
|
+
|
96
|
+
Masheri::Service.find_each do |entry|
|
97
|
+
entry.should be_a(Masheri::Service)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|