rack-parser 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rack-parser.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2011 Arthur Chiu
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
@@ -0,0 +1,82 @@
1
+ # Rack::Parser #
2
+
3
+ Rack::Parser is a Rack Middleware for parsing post body data for JSON/XML, and custom
4
+ content types using MultiJson, MultiXML, or any thing that you want to
5
+ use.
6
+
7
+ What this allows your rack application to do is decode/parse incoming post data
8
+ into param hashes for your applications to use.
9
+
10
+ ## Installation ##
11
+
12
+ install it via rubygems:
13
+
14
+ ```
15
+ gem install rack-parser
16
+ ```
17
+
18
+ or put it in your Gemfile:
19
+
20
+ ```ruby
21
+ # Gemfile
22
+
23
+ gem 'rack-parser', :require => 'rack/parser'
24
+ ```
25
+
26
+
27
+ ## Usage ##
28
+
29
+
30
+ In a Sinatra or [Padrino](http://padrinorb.com) application, it would probably be something like:
31
+
32
+ ```ruby
33
+ # app.rb
34
+
35
+ use Rack::Parser, :content_types => {
36
+ 'application/json' => Proc.new { |body| MultiJson.decode body },
37
+ 'application/xml' => Proc.new { |body| MultiXml.decode body },
38
+ 'application/roll' => Proc.new { |body| 'never gonna give you up' }
39
+ }
40
+ ```
41
+
42
+
43
+ By default, Rack::Parser uses MultiJson and MultiXml to decode/parse
44
+ your JSON/XML Data. these can be overwritten if you choose not to use
45
+ them. However, through using them you can just as easily leverage the
46
+ engine of your choice by setting the engine like so:
47
+
48
+
49
+ ```ruby
50
+ # app.rb
51
+
52
+ MultiJson.engine = :yajl # Yajl-ruby for json decoding
53
+ MultiXml.parser = :libxml # libxml for XML parsing
54
+
55
+ use Rack::Parser, :content_types => {
56
+ 'application/json' => Proc.new { |body| MultiJson.decode body },
57
+ 'application/xml' => Proc.new { |body| MultiXml.decode body },
58
+ 'application/roll' => Proc.new { |body| 'never gonna give you up' }
59
+ }
60
+ ```
61
+
62
+ To set your own custom engine that perhaps neither MultiJson or MultiXml
63
+ support, just make it a Proc:
64
+
65
+
66
+ ```ruby
67
+ use Rack::Parser, :content_types => {
68
+ 'application/json' => Proc.new { |body| MyCustomJsonEngine.do_it body }
69
+ }
70
+ ```
71
+
72
+ ## Inspirations ##
73
+
74
+ This project came to being because of:
75
+
76
+ * [Niko Dittmann's](https://www.github.com/niko) [rack-post-body-to-params](https://www.github.com/niko/rack-post-body-to-params) which some of its ideas are instilled in this middleware.
77
+ * Rack::PostBodyContentTypeParser from rack-contrib which proved to be an inspiration for both libraries.
78
+
79
+ ## Copyright
80
+
81
+ Copyright © 2011 Arthur Chiu. See [MIT-LICENSE](https://github.com/achiu/rack-parser/blob/master/MIT-LICENSE) for details.
82
+
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rake/testtask'
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'lib' << 'test'
6
+ test.pattern = 'test/**/*_test.rb'
7
+ test.verbose = true
8
+ test.ruby_opts << '-rubygems'
9
+ end
@@ -0,0 +1,59 @@
1
+ require 'multi_json'
2
+ require 'multi_xml'
3
+
4
+ module Rack
5
+
6
+ # Rack::Parser allows you to set custom parsers for incoming post body data. As a default,
7
+ # Rack::Parser uses MultiJson and MultiXml to do the decoding/parsing for you. This allows you to
8
+ # designate any engine you wish that is compatible with the MultiJson/MultiXml libraries.
9
+ # You can also conveniently use another library by as well by wrapping it as a Proc or add additional
10
+ # content types which are not default in this middleware.
11
+ #
12
+ class Parser
13
+
14
+ # Rack Constants
15
+ HEADER_CONTENT_TYPE = 'Content-Type'.freeze
16
+ POST_BODY = 'rack.input'.freeze
17
+ FORM_INPUT = 'rack.request.form_input'.freeze
18
+ FORM_HASH = 'rack.request.form_hash'.freeze
19
+
20
+ # Default Settings
21
+ DEFAULT_CONTENT_TYPE = {
22
+ 'application/xml' => Proc.new { |body| MultiXml.parse(body) },
23
+ 'application/json' => Proc.new { |body| MultiJson.decode(body) }
24
+ }
25
+
26
+ attr_reader :content_types
27
+
28
+ # Usage:
29
+ # use Rack::Parser, :content_types = {
30
+ # 'application/xml' => Proc.new { |body| XmlParser.parse body } # if you don't want the default
31
+ # 'application/json' => Proc.new { |body| JsonParser.decode body } # if you don't want the default
32
+ # 'application/foo' => Proc.new { |body| FooParser.parse body }
33
+ # }
34
+ def initialize(app, options = {})
35
+ @app = app
36
+ @content_types = DEFAULT_CONTENT_TYPE.merge(options.delete(:content_types) || {})
37
+ end
38
+
39
+ def call(env)
40
+ dup._call(env)
41
+ end
42
+
43
+ def _call(env)
44
+ body = env[POST_BODY].read
45
+ return @app.call(env) if (body.respond_to?(:empty?) ? body.empty? : !body) # Send it down the stack immediately
46
+ content_type = env[HEADER_CONTENT_TYPE]
47
+ format = content_type.split('/').last
48
+ begin
49
+ result = @content_types[content_type].call(body)
50
+ env.update FORM_HASH => result, FORM_INPUT => body
51
+ @app.call env
52
+ rescue Exception => e
53
+ logger.warn "#{self.class} #{content_type} parsing error: #{e.to_s}" if respond_to? :logger # Send to logger if its there.
54
+ [400, { 'Content-Type' => content_type }, [ {'errors' => e.to_s}.method("to_#{format}").call ] ] # Finally, return an error response.
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "rack-parser"
6
+ s.version = "0.0.1"
7
+ s.authors = ["Arthur Chiu"]
8
+ s.email = ["mr.arthur.chiu@gmail.com"]
9
+ s.homepage = ""
10
+ s.summary = %q{Rack Middleware for parsing post body data}
11
+ s.description = %q{Rack Middleware for parsing post body data for json/xml and various content types}
12
+
13
+ s.rubyforge_project = "rack-parser"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency 'rack'
21
+ s.add_dependency 'multi_json'
22
+ s.add_dependency 'multi_xml'
23
+ s.add_development_dependency 'riot'
24
+ s.add_development_dependency 'rack-test'
25
+ s.add_development_dependency 'json'
26
+ end
@@ -0,0 +1,66 @@
1
+ require File.expand_path('../teststrap', __FILE__)
2
+
3
+ class FooApp
4
+ def call(env); env; end
5
+ end
6
+
7
+ context "Rack::Parser" do
8
+
9
+ context "default configuration" do
10
+ setup do
11
+ Rack::Parser.new(FooApp.new).content_types
12
+ end
13
+
14
+ asserts(:[],'application/xml').kind_of Proc
15
+ asserts(:[],'application/json').kind_of Proc
16
+ end
17
+
18
+ context "with custom configuration" do
19
+ setup do
20
+ Rack::Parser.new(FooApp.new, :content_types => {
21
+ 'application/xml' => :meh,
22
+ 'application/foo' => :bar
23
+ }).content_types
24
+ end
25
+
26
+ asserts(:[], 'application/xml').equals :meh
27
+ asserts(:[], 'application/foo').equals :bar
28
+ end
29
+
30
+ context "with json" do
31
+ setup do
32
+ post '/post', "{\"test\":1,\"foo\":2,\"bar\":\"3\"}", { 'Content-Type' => 'application/json' }
33
+ end
34
+
35
+ asserts(:status).equals 200
36
+ asserts(:body).equals "{\"test\"=>1, \"foo\"=>2, \"bar\"=>\"3\"}"
37
+ end
38
+
39
+ context "with xml" do
40
+ setup do
41
+ put '/post', "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <a type=\"integer\">1</a>\n</hash>\n", { 'Content-Type' => 'application/xml'}
42
+ end
43
+
44
+ asserts(:status).equals 200
45
+ asserts(:body).equals "{\"hash\"=>{\"a\"=>1}}"
46
+ end
47
+
48
+ context "with custom 'foo'" do
49
+ setup do
50
+ post '/post', 'something that does not matter', { 'Content-Type' => 'application/foo' }
51
+ end
52
+
53
+ asserts(:status).equals 200
54
+ asserts(:body).equals 'foo'
55
+ end
56
+
57
+ context "with bad data" do
58
+ setup do
59
+ post '/post', "fuuuuuuuuuu", { 'Content-Type' => 'application/json' }
60
+ end
61
+
62
+ asserts(:status).equals 400
63
+ asserts(:body).equals "{\"errors\":\"706: unexpected token at 'fuuuuuuuuuu'\"}"
64
+ end
65
+
66
+ end
@@ -0,0 +1,33 @@
1
+ require 'rack'
2
+ require 'riot'
3
+ require 'rack/test'
4
+ require 'rack/builder'
5
+ require 'json'
6
+
7
+ require File.expand_path('../../lib/rack/parser', __FILE__)
8
+
9
+ class Riot::Situation
10
+ include Rack::Test::Methods
11
+
12
+ def app
13
+ main_app = lambda { |env|
14
+ request = Rack::Request.new(env)
15
+ return_code, body_text =
16
+ case request.path
17
+ when '/' then [200,'Hello world']
18
+ when '/post' then [200, env['rack.request.form_hash']]
19
+ else
20
+ [404,'Nothing here']
21
+ end
22
+ [return_code,{'Content-type' => 'text/plain'}, [body_text]]
23
+ }
24
+
25
+ builder = Rack::Builder.new
26
+ builder.use Rack::Parser, :content_types => { 'application/foo' => Proc.new { |b| 'foo' } }
27
+ builder.run main_app
28
+ builder.to_app
29
+ end
30
+ end
31
+
32
+ class Riot::Context
33
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-parser
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Arthur Chiu
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-07-13 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rack
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: multi_json
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :runtime
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: multi_xml
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: riot
50
+ prerelease: false
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ type: :development
58
+ version_requirements: *id004
59
+ - !ruby/object:Gem::Dependency
60
+ name: rack-test
61
+ prerelease: false
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ type: :development
69
+ version_requirements: *id005
70
+ - !ruby/object:Gem::Dependency
71
+ name: json
72
+ prerelease: false
73
+ requirement: &id006 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ type: :development
80
+ version_requirements: *id006
81
+ description: Rack Middleware for parsing post body data for json/xml and various content types
82
+ email:
83
+ - mr.arthur.chiu@gmail.com
84
+ executables: []
85
+
86
+ extensions: []
87
+
88
+ extra_rdoc_files: []
89
+
90
+ files:
91
+ - .gitignore
92
+ - Gemfile
93
+ - MIT-LICENSE
94
+ - README.md
95
+ - Rakefile
96
+ - lib/rack/parser.rb
97
+ - rack-parser.gemspec
98
+ - test/parser_test.rb
99
+ - test/teststrap.rb
100
+ homepage: ""
101
+ licenses: []
102
+
103
+ post_install_message:
104
+ rdoc_options: []
105
+
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: "0"
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: "0"
120
+ requirements: []
121
+
122
+ rubyforge_project: rack-parser
123
+ rubygems_version: 1.8.4
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: Rack Middleware for parsing post body data
127
+ test_files:
128
+ - test/parser_test.rb
129
+ - test/teststrap.rb