rhn 0.0.3
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.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +75 -0
- data/LICENSE.txt +22 -0
- data/Makefile +7 -0
- data/README.md +45 -0
- data/Rakefile +3 -0
- data/bin/rhn +7 -0
- data/config.ru +6 -0
- data/lib/rhn/apigen.rb +62 -0
- data/lib/rhn/app.rb +31 -0
- data/lib/rhn/controllers.rb +20 -0
- data/lib/rhn/util.rb +12 -0
- data/lib/rhn/version.rb +3 -0
- data/lib/rhn.rb +5 -0
- data/rhn.gemspec +37 -0
- data/spec/api_gen_spec.rb +82 -0
- data/spec/api_spec.rb +36 -0
- data/spec/api_web_acces_spec.rb +104 -0
- data/spec/spec_helper.rb +29 -0
- metadata +184 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Yjg1OWY2MWU0Y2VjZGY1NWIyOTI5ZThmZDIxMTQzNjhmMTY1YzViNQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NDg0MDU3NzBlZjQzM2JlNjNiODhiNjFlZmY4YThhZWFiOTc5YjFhNg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
Njk0N2NjODhkZmZjY2ZlMWYwM2QzOGE3OGFmYzVhZWZkNWZlNmM3Mzc4M2Jm
|
10
|
+
MTM3Zjc2OTlmYjI3MTk2ZjRhOWZkNTQ4M2M5YjA2ODY5ZjQxYTc2N2Q3YjQw
|
11
|
+
ZDFiNzgyNTFmMDFlNWNhZmEyZWRkYmNiM2U4NjVhNjY4NjE4ZjE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
OGMzNDc0NDY2M2QzMWJkZTRkZDc3YjRkYzdjZGQzZDJjYjA4ZTMxNzYyYThl
|
14
|
+
ODc1MWU3OTU5ODk5YjRiOGU4OGE0MzUxYTRhNDA2ZDNiOThiNTk1OTgzZjZi
|
15
|
+
MjZjYWExMDgxN2Y5NTJmYTYxMjc3YTVkYjQ4YzZjZjZiMjFjZTU=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rhn (0.0.3)
|
5
|
+
json
|
6
|
+
ruby-hackernews
|
7
|
+
sinatra
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
bump (0.4.2)
|
13
|
+
columnize (0.3.6)
|
14
|
+
debugger (1.6.1)
|
15
|
+
columnize (>= 0.3.1)
|
16
|
+
debugger-linecache (~> 1.2.0)
|
17
|
+
debugger-ruby_core_source (~> 1.2.3)
|
18
|
+
debugger-linecache (1.2.0)
|
19
|
+
debugger-ruby_core_source (1.2.3)
|
20
|
+
diff-lcs (1.2.4)
|
21
|
+
domain_name (0.5.9)
|
22
|
+
unf (>= 0.0.5, < 1.0.0)
|
23
|
+
json (1.8.0)
|
24
|
+
mechanize (2.6.0)
|
25
|
+
domain_name (~> 0.5, >= 0.5.1)
|
26
|
+
mime-types (~> 1.17, >= 1.17.2)
|
27
|
+
net-http-digest_auth (~> 1.1, >= 1.1.1)
|
28
|
+
net-http-persistent (~> 2.5, >= 2.5.2)
|
29
|
+
nokogiri (~> 1.4)
|
30
|
+
ntlm-http (~> 0.1, >= 0.1.1)
|
31
|
+
webrobots (>= 0.0.9, < 0.2)
|
32
|
+
mime-types (1.24)
|
33
|
+
mini_portile (0.5.1)
|
34
|
+
net-http-digest_auth (1.2.1)
|
35
|
+
net-http-persistent (2.8)
|
36
|
+
nokogiri (1.6.0)
|
37
|
+
mini_portile (~> 0.5.0)
|
38
|
+
ntlm-http (0.1.1)
|
39
|
+
rack (1.5.2)
|
40
|
+
rack-protection (1.5.0)
|
41
|
+
rack
|
42
|
+
rack-test (0.6.2)
|
43
|
+
rack (>= 1.0)
|
44
|
+
require_all (1.2.1)
|
45
|
+
rspec (2.14.1)
|
46
|
+
rspec-core (~> 2.14.0)
|
47
|
+
rspec-expectations (~> 2.14.0)
|
48
|
+
rspec-mocks (~> 2.14.0)
|
49
|
+
rspec-core (2.14.5)
|
50
|
+
rspec-expectations (2.14.2)
|
51
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
52
|
+
rspec-mocks (2.14.3)
|
53
|
+
ruby-hackernews (1.3.3)
|
54
|
+
mechanize (>= 1.0.0)
|
55
|
+
require_all (>= 1.1.0)
|
56
|
+
sinatra (1.4.3)
|
57
|
+
rack (~> 1.4)
|
58
|
+
rack-protection (~> 1.4)
|
59
|
+
tilt (~> 1.3, >= 1.3.4)
|
60
|
+
tilt (1.4.1)
|
61
|
+
unf (0.1.1)
|
62
|
+
unf_ext
|
63
|
+
unf_ext (0.0.6)
|
64
|
+
webrobots (0.1.1)
|
65
|
+
|
66
|
+
PLATFORMS
|
67
|
+
ruby
|
68
|
+
|
69
|
+
DEPENDENCIES
|
70
|
+
bump
|
71
|
+
bundler (~> 1.3)
|
72
|
+
debugger
|
73
|
+
rack-test
|
74
|
+
rhn!
|
75
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Lincoln de Sousa
|
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/Makefile
ADDED
data/README.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# RHN
|
2
|
+
|
3
|
+
Yet another WEB API for hackernews. Beware of lazy hack ahead!
|
4
|
+
This project is a very thin layer on top of [ruby-hackernews](https://github.com/bolthar/ruby-hackernews) so
|
5
|
+
we can access this info through HTTP.
|
6
|
+
|
7
|
+
The main usage of this API is an [Emacs Client for Hackernews](https://github.com/clarete/hackernews.el).
|
8
|
+
|
9
|
+
## Install and Run
|
10
|
+
|
11
|
+
That's easy. You just have to get the code and run the `rhn` executable:
|
12
|
+
|
13
|
+
$ gem install rhn
|
14
|
+
|
15
|
+
Boom! Just change your emacs configuration adding the following lines:
|
16
|
+
|
17
|
+
(setq hackernews-url "http://127.0.0.1:4567/")
|
18
|
+
|
19
|
+
The next time you run `M-x hackernews` you'll be using your local proxy.
|
20
|
+
|
21
|
+
## As a library
|
22
|
+
|
23
|
+
Add this line to your application's Gemfile
|
24
|
+
|
25
|
+
gem 'rhn'
|
26
|
+
|
27
|
+
And then execute
|
28
|
+
|
29
|
+
$ bundle
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
$ rhn
|
34
|
+
|
35
|
+
Then open a browser and try the following URL:
|
36
|
+
|
37
|
+
http://localhost:4567/api/?r=%7B%22symbol%22%3A%22HN.hotpage%22%7D
|
38
|
+
|
39
|
+
## Contributing
|
40
|
+
|
41
|
+
1. Fork it
|
42
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
43
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
44
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
45
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/rhn
ADDED
data/config.ru
ADDED
data/lib/rhn/apigen.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
module ApiGen
|
2
|
+
|
3
|
+
class AccessDenied < Exception
|
4
|
+
end
|
5
|
+
|
6
|
+
class NotFound < Exception
|
7
|
+
end
|
8
|
+
|
9
|
+
class Entry
|
10
|
+
attr_accessor :factory, :symbols
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@factory = nil
|
14
|
+
@symbols = []
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
class AccessManager
|
20
|
+
|
21
|
+
@@REGISTRY = {}
|
22
|
+
|
23
|
+
def self.register factory, symbol
|
24
|
+
entry = Entry.new
|
25
|
+
entry.factory = factory
|
26
|
+
entry.symbols.push symbol
|
27
|
+
|
28
|
+
@@REGISTRY[factory.name] = entry
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.get name
|
32
|
+
@@REGISTRY[name]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
class Resolver
|
38
|
+
attr_accessor :symbol
|
39
|
+
|
40
|
+
def initialize symbol
|
41
|
+
@symbol = symbol
|
42
|
+
end
|
43
|
+
|
44
|
+
def v *args
|
45
|
+
base, subpath = @symbol.split '.'
|
46
|
+
|
47
|
+
entry = AccessManager.get base
|
48
|
+
raise NotFound, "There's no such object" if entry.nil?
|
49
|
+
|
50
|
+
found = entry.symbols.include?(subpath)
|
51
|
+
raise AccessDenied, "You don't have access to this resource" if not found
|
52
|
+
|
53
|
+
inst = entry.factory.new
|
54
|
+
inst.send subpath.to_sym, *args
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def from_dsl description
|
59
|
+
Resolver.new(description[:symbol]).v(*(description[:args] || []))
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
data/lib/rhn/app.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'json'
|
3
|
+
require 'ruby-hackernews'
|
4
|
+
|
5
|
+
require 'rhn/util'
|
6
|
+
require 'rhn/apigen'
|
7
|
+
require 'rhn/controllers'
|
8
|
+
|
9
|
+
include ApiGen
|
10
|
+
|
11
|
+
|
12
|
+
class RHN < Sinatra::Base
|
13
|
+
get '/api/' do
|
14
|
+
begin
|
15
|
+
decoded = decode_req params[:r]
|
16
|
+
result = {:result => from_dsl(decoded)}
|
17
|
+
rescue AccessDenied => exc
|
18
|
+
status 550
|
19
|
+
result = {:error => exc.to_s}
|
20
|
+
rescue NotFound => exc
|
21
|
+
status 404
|
22
|
+
result = {:error => exc.to_s}
|
23
|
+
rescue JSON::ParserError
|
24
|
+
status 400
|
25
|
+
result = {:error => "The parameter you passed couldn't be parsed"}
|
26
|
+
end
|
27
|
+
|
28
|
+
content_type :json
|
29
|
+
result.to_json
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'ruby-hackernews'
|
2
|
+
require 'rhn/apigen'
|
3
|
+
|
4
|
+
|
5
|
+
class HN
|
6
|
+
def hotpage
|
7
|
+
RubyHackernews::Entry.all.map {|entry|
|
8
|
+
{
|
9
|
+
:id => entry.id.to_i,
|
10
|
+
:title => entry.link.title,
|
11
|
+
:link => entry.link.href,
|
12
|
+
:comments_count => entry.comments_count.to_i,
|
13
|
+
:voting => entry.voting.score.to_i,
|
14
|
+
:user => entry.user.name
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
ApiGen::AccessManager.register HN, "hotpage"
|
data/lib/rhn/util.rb
ADDED
data/lib/rhn/version.rb
ADDED
data/lib/rhn.rb
ADDED
data/rhn.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- mode: ruby; coding: utf-8; -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rhn/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rhn"
|
8
|
+
spec.version = Rhn::VERSION
|
9
|
+
spec.authors = ["Lincoln de Sousa"]
|
10
|
+
spec.email = ["lincoln@clarete.li"]
|
11
|
+
spec.description = %q{Yet another WEB API for hackernews}
|
12
|
+
spec.summary = %q{Yet another WEB API for hackernews. Beware of lazy hack ahead!
|
13
|
+
This project is a very thin layer on top of [ruby-hackernews](https://github.com/bolthar/ruby-hackernews) so
|
14
|
+
we can access this info through HTTP.
|
15
|
+
|
16
|
+
The main usage of this API is an [Emacs Client for Hackernews](https://github.com/clarete/hackernews.el).
|
17
|
+
}
|
18
|
+
spec.homepage = ""
|
19
|
+
spec.license = "MIT"
|
20
|
+
|
21
|
+
spec.files = `git ls-files`.split($/)
|
22
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
23
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
# Library requirements
|
27
|
+
spec.add_dependency "ruby-hackernews"
|
28
|
+
spec.add_dependency "sinatra"
|
29
|
+
spec.add_dependency "json"
|
30
|
+
|
31
|
+
# Development requirements
|
32
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
33
|
+
spec.add_development_dependency "debugger"
|
34
|
+
spec.add_development_dependency "rspec"
|
35
|
+
spec.add_development_dependency "rack-test"
|
36
|
+
spec.add_development_dependency "bump"
|
37
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'rhn/apigen'
|
2
|
+
|
3
|
+
include ApiGen
|
4
|
+
|
5
|
+
describe "Access Manager" do
|
6
|
+
it "should register objects and provide access for them through a resolver" do
|
7
|
+
|
8
|
+
# Given that I have a random python object declared somewhere in my
|
9
|
+
# computer
|
10
|
+
class RandomObject
|
11
|
+
def get_stuff_1
|
12
|
+
"blah"
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_stuff_2
|
16
|
+
"bleh"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# When I allow the object and a method to be accessed by my crazy API
|
21
|
+
AccessManager.register RandomObject, "get_stuff_1"
|
22
|
+
|
23
|
+
# Then I see that now the registered method (get_stuff_1) is available but
|
24
|
+
# the other one (get_stuff_2) remains protected
|
25
|
+
Resolver.new("RandomObject.get_stuff_1").v.should be_eql("blah")
|
26
|
+
expect { Resolver.new("RandomObject.get_stuff_2").v }.to raise_error AccessDenied, "You don't have access to this resource"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return a smart message when the object does not exist" do
|
30
|
+
expect {
|
31
|
+
Resolver.new("NoSuchObject.no_such_method").v
|
32
|
+
}.to raise_error NotFound, "There's no such object"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should provide access to attributes" do
|
36
|
+
# Given that I have a random object with an attribute
|
37
|
+
class RandomObject
|
38
|
+
attr_accessor :attr
|
39
|
+
|
40
|
+
def initialize
|
41
|
+
@attr = 'random value'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# When I register the attr through the AccessManager
|
46
|
+
AccessManager.register RandomObject, 'attr'
|
47
|
+
|
48
|
+
# Then I see that I can retrieve the right value
|
49
|
+
Resolver.new('RandomObject.attr').v.should be_eql('random value')
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should access method that takes parameters" do
|
53
|
+
# Given that I have a class with a method that takes parameters
|
54
|
+
class RandomObject
|
55
|
+
def sum a, b
|
56
|
+
a + b
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# When I register the attr in the AccessManager
|
61
|
+
AccessManager.register RandomObject, 'sum'
|
62
|
+
|
63
|
+
# Then I see that it's possible to pass arguments to my function
|
64
|
+
Resolver.new('RandomObject.sum').v(2, 2).should be_eql(4)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should provide an easier way to resolve symbols" do
|
68
|
+
# Given that I have a class with a method that takes parameters and
|
69
|
+
# properly registered in the access manager
|
70
|
+
class RandomObject
|
71
|
+
def sum a, b
|
72
|
+
a + b
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
AccessManager.register RandomObject, 'sum'
|
77
|
+
|
78
|
+
# When I query for the symbol using a dsl-ish description contained in a
|
79
|
+
# dictionary, I see that I still get my results! :)
|
80
|
+
ApiGen::from_dsl({:symbol => 'RandomObject.sum', :args => [2, 2]}).should be_eql(4)
|
81
|
+
end
|
82
|
+
end
|
data/spec/api_spec.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'ruby-hackernews'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
require 'rhn/util'
|
5
|
+
|
6
|
+
|
7
|
+
describe "Hackernews", "#hotpage" do
|
8
|
+
it "It should return the list of posts on the hot page" do
|
9
|
+
# Given that we mock some posts
|
10
|
+
RubyHackernews::Entry.should_receive(:all).and_return [
|
11
|
+
mock_entry("1", "My post", "http://blog.c.o/p/1", 223, 12345, "clarete"),
|
12
|
+
mock_entry("2", "Another post", "http://blog.c.o/p/22", 239, 3433, "guerrinha")]
|
13
|
+
|
14
|
+
# When we request the hotpage posts
|
15
|
+
desc = encode_req({:symbol => 'HN.hotpage'})
|
16
|
+
get "/api/?r=#{desc}"
|
17
|
+
|
18
|
+
# Then I see that I got all the entries available
|
19
|
+
JSON.parse(last_response.body, :symbolize_names => true).should be_eql(
|
20
|
+
{:result => [
|
21
|
+
{:id => 1,
|
22
|
+
:title => "My post",
|
23
|
+
:link => "http://blog.c.o/p/1",
|
24
|
+
:comments_count => 223,
|
25
|
+
:voting => 12345,
|
26
|
+
:user => "clarete"},
|
27
|
+
{:id => 2,
|
28
|
+
:title => "Another post",
|
29
|
+
:link => "http://blog.c.o/p/22",
|
30
|
+
:comments_count => 239,
|
31
|
+
:voting => 3433,
|
32
|
+
:user => "guerrinha"}
|
33
|
+
]}
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'json'
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
require 'rhn/util'
|
6
|
+
require 'rhn/apigen'
|
7
|
+
|
8
|
+
describe "Web Access" do
|
9
|
+
|
10
|
+
it "should be possible to encode requested symbols" do
|
11
|
+
# Given that I have a request to the API described in the mini-dsl lang
|
12
|
+
req = {"symbol" => 'MyObject', "args" => [1, 2]}
|
13
|
+
|
14
|
+
# When I prepare the request
|
15
|
+
prepared = encode_req(req)
|
16
|
+
|
17
|
+
# Then I see that it was transformed into a json string encoded by the
|
18
|
+
# ruby's `CGI::escape` function.
|
19
|
+
JSON.parse(CGI::unescape(prepared)).should be_eql(req)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should be possible to decode requested symbols" do
|
23
|
+
# Given that I have an encoded param
|
24
|
+
encoded_req = \
|
25
|
+
'%7B%22symbol%22%3A+%22MyObject%22%2C+%22args%22%3A+%5B1%2C+2%5D%7D'
|
26
|
+
|
27
|
+
# When I decode the param above
|
28
|
+
decoded = decode_req(encoded_req)
|
29
|
+
|
30
|
+
# Then I see that it was transformed in a dict
|
31
|
+
decoded.should be_eql({:symbol => 'MyObject', :args => [1, 2]})
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should provide access for classes registered in the access manager" do
|
35
|
+
|
36
|
+
# Given that I have an object registered in the AccessManager
|
37
|
+
class Stuff
|
38
|
+
def mul a, b
|
39
|
+
a * b
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
ApiGen::AccessManager.register Stuff, 'mul'
|
44
|
+
|
45
|
+
# When I hit the API that resolves objects with the right parameters
|
46
|
+
desc = encode_req({:symbol => 'Stuff.mul', :args => [2, 2]})
|
47
|
+
get "/api/?r=#{desc}"
|
48
|
+
|
49
|
+
# Then I see that the result was right
|
50
|
+
last_response.status.should be_eql 200
|
51
|
+
last_response.headers["content-type"].should be_eql "application/json;charset=utf-8"
|
52
|
+
JSON.parse(last_response.body).should be_eql({'result' => 4})
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should return an error code when the user tries to access denied resources" do
|
56
|
+
# Given that I have an object registered in the AccessManager with
|
57
|
+
# unregistered symbols
|
58
|
+
class Calc
|
59
|
+
def sum a, b
|
60
|
+
a + b
|
61
|
+
end
|
62
|
+
def mul a, b
|
63
|
+
a * b
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
ApiGen::AccessManager.register Calc, 'mul'
|
68
|
+
|
69
|
+
# When I try to access the unregistered symbol
|
70
|
+
desc = encode_req({:symbol => 'Stuff.sum', :args => [2, 2]})
|
71
|
+
get "/api/?r=#{desc}"
|
72
|
+
|
73
|
+
# Then I receive an error message saying that I have no permission to
|
74
|
+
# access that
|
75
|
+
last_response.status.should be_eql 550
|
76
|
+
last_response.headers["content-type"].should be_eql "application/json;charset=utf-8"
|
77
|
+
JSON.parse(last_response.body).should be_eql({'error' => "You don't have access to this resource"})
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return the proper status and message when the resource is not found" do
|
81
|
+
# When I try to access the unregistered object
|
82
|
+
desc = encode_req({:symbol => 'NoSuchObj.no_such_method', :args => [2, 2]})
|
83
|
+
get "/api/?r=#{desc}"
|
84
|
+
|
85
|
+
# Then I should see the proper error message raised with a nice message
|
86
|
+
last_response.status.should be_eql 404
|
87
|
+
last_response.headers["content-type"].should be_eql "application/json;charset=utf-8"
|
88
|
+
JSON.parse(last_response.body).should be_eql({'error' => "There's no such object"})
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should handle invalid requests with the right status and nice message" do
|
92
|
+
# Given that I have a buggy query parameter
|
93
|
+
query = 'invalid'
|
94
|
+
|
95
|
+
# When I hit the API end point with that invalid param
|
96
|
+
get "/api/?r=#{query}"
|
97
|
+
|
98
|
+
# Then I see that a proper error message was set
|
99
|
+
last_response.status.should be_eql 400
|
100
|
+
last_response.headers["content-type"].should be_eql "application/json;charset=utf-8"
|
101
|
+
JSON.parse(last_response.body).should be_eql(
|
102
|
+
{'error' => "The parameter you passed couldn't be parsed"})
|
103
|
+
end
|
104
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rack/test'
|
2
|
+
require 'sinatra'
|
3
|
+
require 'ruby-hackernews'
|
4
|
+
|
5
|
+
require 'rhn/app'
|
6
|
+
|
7
|
+
# setup test environment
|
8
|
+
set :environment, :test
|
9
|
+
set :run, false
|
10
|
+
set :raise_errors, true
|
11
|
+
set :logging, false
|
12
|
+
|
13
|
+
def app
|
14
|
+
RHN
|
15
|
+
end
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
config.include Rack::Test::Methods
|
19
|
+
end
|
20
|
+
|
21
|
+
def mock_entry id, title, link, ccount, voting, user
|
22
|
+
link = mock(Object, :title => title, :href => link)
|
23
|
+
mock(RubyHackernews::Entry,
|
24
|
+
:id => id,
|
25
|
+
:link => link,
|
26
|
+
:comments_count => ccount,
|
27
|
+
:voting => mock(Object, :score => voting),
|
28
|
+
:user => mock(Object, :name => user))
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rhn
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Lincoln de Sousa
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ruby-hackernews
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sinatra
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: json
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: debugger
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rack-test
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: bump
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: Yet another WEB API for hackernews
|
126
|
+
email:
|
127
|
+
- lincoln@clarete.li
|
128
|
+
executables:
|
129
|
+
- rhn
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- .gitignore
|
134
|
+
- Gemfile
|
135
|
+
- Gemfile.lock
|
136
|
+
- LICENSE.txt
|
137
|
+
- Makefile
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- bin/rhn
|
141
|
+
- config.ru
|
142
|
+
- lib/rhn.rb
|
143
|
+
- lib/rhn/apigen.rb
|
144
|
+
- lib/rhn/app.rb
|
145
|
+
- lib/rhn/controllers.rb
|
146
|
+
- lib/rhn/util.rb
|
147
|
+
- lib/rhn/version.rb
|
148
|
+
- rhn.gemspec
|
149
|
+
- spec/api_gen_spec.rb
|
150
|
+
- spec/api_spec.rb
|
151
|
+
- spec/api_web_acces_spec.rb
|
152
|
+
- spec/spec_helper.rb
|
153
|
+
homepage: ''
|
154
|
+
licenses:
|
155
|
+
- MIT
|
156
|
+
metadata: {}
|
157
|
+
post_install_message:
|
158
|
+
rdoc_options: []
|
159
|
+
require_paths:
|
160
|
+
- lib
|
161
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - ! '>='
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '0'
|
171
|
+
requirements: []
|
172
|
+
rubyforge_project:
|
173
|
+
rubygems_version: 2.1.9
|
174
|
+
signing_key:
|
175
|
+
specification_version: 4
|
176
|
+
summary: Yet another WEB API for hackernews. Beware of lazy hack ahead! This project
|
177
|
+
is a very thin layer on top of [ruby-hackernews](https://github.com/bolthar/ruby-hackernews)
|
178
|
+
so we can access this info through HTTP. The main usage of this API is an [Emacs
|
179
|
+
Client for Hackernews](https://github.com/clarete/hackernews.el).
|
180
|
+
test_files:
|
181
|
+
- spec/api_gen_spec.rb
|
182
|
+
- spec/api_spec.rb
|
183
|
+
- spec/api_web_acces_spec.rb
|
184
|
+
- spec/spec_helper.rb
|