cryx-g5k 0.1.0
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/lib/g5k/parsing/parser.rb +47 -0
- data/lib/g5k/parsing.rb +7 -0
- data/lib/g5k/rack/accept_format.rb +46 -0
- data/lib/g5k/rack/jsonp.rb +43 -0
- data/lib/g5k/sinatra/helpers.rb +32 -0
- data/lib/g5k.rb +5 -0
- data/spec/g5k_spec.rb +4 -0
- data/spec/parsing_spec.rb +44 -0
- data/spec/spec_helper.rb +9 -0
- metadata +68 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
module G5K
|
2
|
+
module Parsing
|
3
|
+
class UnsupportedFormat < StandardError; end
|
4
|
+
class Parser
|
5
|
+
@@parsers = []
|
6
|
+
def self.add(*parsers)
|
7
|
+
parsers.each{ |parser|
|
8
|
+
parser.dependencies
|
9
|
+
@@parsers << parser
|
10
|
+
}
|
11
|
+
self
|
12
|
+
end
|
13
|
+
def self.select(parser_format)
|
14
|
+
raise UnsupportedFormat, "The format cannot be nil." if parser_format.nil?
|
15
|
+
parsers = @@parsers.select{|parser| parser.supported_formats.include?(parser_format.to_sym)}
|
16
|
+
if parsers.empty?
|
17
|
+
raise UnsupportedFormat, "No parser found for '#{parser_format}' format."
|
18
|
+
else
|
19
|
+
parsers.first
|
20
|
+
end
|
21
|
+
end
|
22
|
+
def self.available_parsers; @@parsers; end
|
23
|
+
end
|
24
|
+
|
25
|
+
class JSONParser
|
26
|
+
def self.dependencies
|
27
|
+
require 'json'
|
28
|
+
end
|
29
|
+
def self.supported_formats
|
30
|
+
[:json]
|
31
|
+
end
|
32
|
+
def self.dump(object, options = {:format => :pretty})
|
33
|
+
case options[:format]
|
34
|
+
when :pretty
|
35
|
+
JSON.pretty_generate object
|
36
|
+
else
|
37
|
+
object.to_json
|
38
|
+
end
|
39
|
+
end
|
40
|
+
def self.load(object)
|
41
|
+
JSON.parse(object)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Parser.add(JSONParser)
|
46
|
+
end
|
47
|
+
end
|
data/lib/g5k/parsing.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module G5K
|
2
|
+
module Rack
|
3
|
+
#
|
4
|
+
# A Rack middleware for automatically adding a <tt>format</tt> token at the end of the request path
|
5
|
+
# when there is none. It can detect formats passed in the HTTP_ACCEPT header to populate this token.
|
6
|
+
#
|
7
|
+
# e.g.:
|
8
|
+
# GET /some/resource HTTP/1.1
|
9
|
+
# Accept: application/json
|
10
|
+
# ->
|
11
|
+
# GET /some/resource.json HTTP/1.1
|
12
|
+
# Accept: application/json
|
13
|
+
#
|
14
|
+
# You can add custom types with this kind of function (taken from sinatra):
|
15
|
+
# def mime(ext, type)
|
16
|
+
# ext = ".#{ext}" unless ext.to_s[0] == ?.
|
17
|
+
# Rack::Mime::MIME_TYPES[ext.to_s] = type
|
18
|
+
# end
|
19
|
+
# and then:
|
20
|
+
# mime :json, 'application/json'
|
21
|
+
#
|
22
|
+
# Note: it does not take into account multiple media types in the Accept header.
|
23
|
+
# The first media type takes precedence over all the others.
|
24
|
+
#
|
25
|
+
# MIT-License - Cyril Rohr
|
26
|
+
#
|
27
|
+
class AcceptFormat
|
28
|
+
# Constants
|
29
|
+
DEFAULT_EXTENSION = ".html"
|
30
|
+
|
31
|
+
def initialize(app)
|
32
|
+
@app = app
|
33
|
+
end
|
34
|
+
|
35
|
+
def call(env)
|
36
|
+
req = Rack::Request.new(env)
|
37
|
+
unless req.path_info =~ /(.*)\.(.+)/
|
38
|
+
accept = env['HTTP_ACCEPT'].scan(/[^;,\s]*\/[^;,\s]*/)[0] rescue ""
|
39
|
+
extension = Rack::Mime::MIME_TYPES.invert[accept] || DEFAULT_EXTENSION
|
40
|
+
req.path_info = req.path_info+"#{extension}"
|
41
|
+
end
|
42
|
+
@app.call(env)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module G5K
|
2
|
+
module Rack
|
3
|
+
|
4
|
+
# A Rack middleware for providing JSON-P support.
|
5
|
+
#
|
6
|
+
# Full credit to Flinn Mueller (http://actsasflinn.com/) for this contribution.
|
7
|
+
#
|
8
|
+
class JSONP
|
9
|
+
|
10
|
+
def initialize(app)
|
11
|
+
@app = app
|
12
|
+
end
|
13
|
+
|
14
|
+
# Proxies the request to the application, stripping out the JSON-P callback
|
15
|
+
# method and padding the response with the appropriate callback format.
|
16
|
+
#
|
17
|
+
# Changes nothing if no <tt>callback</tt> param is specified.
|
18
|
+
#
|
19
|
+
def call(env)
|
20
|
+
status, headers, response = @app.call(env)
|
21
|
+
request = Rack::Request.new(env)
|
22
|
+
if request.params.include?('callback')
|
23
|
+
response = pad(request.params.delete('callback'), response)
|
24
|
+
headers['Content-Length'] = response.length.to_s
|
25
|
+
end
|
26
|
+
[status, headers, response]
|
27
|
+
end
|
28
|
+
|
29
|
+
# Pads the response with the appropriate callback format according to the
|
30
|
+
# JSON-P spec/requirements.
|
31
|
+
#
|
32
|
+
# The Rack response spec indicates that it should be enumerable. The method
|
33
|
+
# of combining all of the data into a single string makes sense since JSON
|
34
|
+
# is returned as a full string.
|
35
|
+
#
|
36
|
+
def pad(callback, response, body = "")
|
37
|
+
response.each{ |s| body << s }
|
38
|
+
"#{callback}(#{body})"
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module G5K
|
2
|
+
module Sinatra
|
3
|
+
module Helpers
|
4
|
+
def returning(thing = nil)
|
5
|
+
yield thing
|
6
|
+
thing
|
7
|
+
end
|
8
|
+
|
9
|
+
def provides *formats
|
10
|
+
if params[:format].nil? || !formats.include?(params[:format].to_sym)
|
11
|
+
throw :halt, [406, "The accepted types are: #{formats.join(", ")}"]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def formatted_error(http_status, options = {})
|
16
|
+
body = {:code => (options[:code] || http_status), :message => options[:message], :title => options[:title]}
|
17
|
+
format = options[:format] || params[:format] || "txt"
|
18
|
+
content_type format.to_sym, :charset => 'utf-8'
|
19
|
+
if (parser = Parser.select(format.to_sym))
|
20
|
+
body = parser.dump(body)
|
21
|
+
else
|
22
|
+
body.map!{|(k,v)| [k,v].join("=")}.join(";")
|
23
|
+
end
|
24
|
+
error(http_status, body)
|
25
|
+
end
|
26
|
+
|
27
|
+
def compute_etag(*differentiators)
|
28
|
+
Digest::SHA1.hexdigest(differentiators.join("."))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/g5k.rb
ADDED
data/spec/g5k_spec.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/g5k/parsing'
|
3
|
+
|
4
|
+
include G5K::Parsing
|
5
|
+
describe "Parsing" do
|
6
|
+
before do
|
7
|
+
require 'rubygems'
|
8
|
+
end
|
9
|
+
it "should add the json parser" do
|
10
|
+
Parser.add(JSONParser).available_parsers.should include(JSONParser)
|
11
|
+
end
|
12
|
+
it "should return an error if a parser is not available for the required format" do
|
13
|
+
Parser.add(JSONParser)
|
14
|
+
lambda{Parser.select(:xml)}.should raise_error(UnsupportedFormat)
|
15
|
+
end
|
16
|
+
it "should raise an UnsupportedFormat if the given format is nil" do
|
17
|
+
lambda{Parser.select(nil)}.should raise_error(UnsupportedFormat)
|
18
|
+
end
|
19
|
+
it "should select the parser for the given format, if made available" do
|
20
|
+
Parser.add(JSONParser)
|
21
|
+
Parser.select(:json).should == JSONParser
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe JSONParser do
|
26
|
+
before do
|
27
|
+
require 'rubygems'
|
28
|
+
end
|
29
|
+
it "should successfully parse a json object" do
|
30
|
+
object = {'a' => 1, 'b' => {'c' => 2, 'd' => [3]}}
|
31
|
+
JSONParser.load(object.to_json).should == object
|
32
|
+
end
|
33
|
+
it "should pretty generate an object" do
|
34
|
+
object = {'a' => 1, 'b' => {'c' => 2, 'd' => [3]}}
|
35
|
+
JSON.should_receive(:pretty_generate).with(object)
|
36
|
+
JSONParser.dump(object, :format => :pretty)
|
37
|
+
end
|
38
|
+
it "should not pretty generate an object" do
|
39
|
+
object = {'a' => 1, 'b' => {'c' => 2, 'd' => [3]}}
|
40
|
+
JSON.should_not_receive(:pretty_generate).with(object)
|
41
|
+
object.should_receive(:to_json)
|
42
|
+
JSONParser.dump(object, :format => :raw)
|
43
|
+
end
|
44
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cryx-g5k
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cyril Rohr
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-02 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Collection of tools and libs for Grid5000 APIs.
|
17
|
+
email: cyril.rohr@irisa.fr
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- VERSION.yml
|
26
|
+
- lib/g5k
|
27
|
+
- lib/g5k/parsing
|
28
|
+
- lib/g5k/parsing/parser.rb
|
29
|
+
- lib/g5k/parsing.rb
|
30
|
+
- lib/g5k/rack
|
31
|
+
- lib/g5k/rack/accept_format.rb
|
32
|
+
- lib/g5k/rack/jsonp.rb
|
33
|
+
- lib/g5k/schema
|
34
|
+
- lib/g5k/sinatra
|
35
|
+
- lib/g5k/sinatra/helpers.rb
|
36
|
+
- lib/g5k.rb
|
37
|
+
- spec/g5k_spec.rb
|
38
|
+
- spec/parsing_spec.rb
|
39
|
+
- spec/spec_helper.rb
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://github.com/cryx/g5k
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options:
|
44
|
+
- --inline-source
|
45
|
+
- --charset=UTF-8
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 1.2.0
|
64
|
+
signing_key:
|
65
|
+
specification_version: 2
|
66
|
+
summary: TODO
|
67
|
+
test_files: []
|
68
|
+
|