response 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/.gitignore +4 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +16 -0
  4. data/Changelog.md +3 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.devtools +60 -0
  7. data/Guardfile +18 -0
  8. data/LICENSE +20 -0
  9. data/README.md +39 -0
  10. data/Rakefile +2 -0
  11. data/TODO +2 -0
  12. data/config/devtools.yml +2 -0
  13. data/config/flay.yml +3 -0
  14. data/config/flog.yml +2 -0
  15. data/config/mutant.yml +3 -0
  16. data/config/reek.yml +92 -0
  17. data/config/roodi.yml +18 -0
  18. data/config/yardstick.yml +2 -0
  19. data/lib/response/html.rb +36 -0
  20. data/lib/response/json.rb +36 -0
  21. data/lib/response/redirect.rb +52 -0
  22. data/lib/response/status.rb +28 -0
  23. data/lib/response/text.rb +37 -0
  24. data/lib/response/xml.rb +36 -0
  25. data/lib/response.rb +271 -0
  26. data/response.gemspec +22 -0
  27. data/spec/rcov.opts +7 -0
  28. data/spec/shared/functional_command_method_behavior.rb +11 -0
  29. data/spec/spec_helper.rb +8 -0
  30. data/spec/unit/response/body_spec.rb +22 -0
  31. data/spec/unit/response/cache_control_spec.rb +25 -0
  32. data/spec/unit/response/class_methods/build_spec.rb +31 -0
  33. data/spec/unit/response/content_type_spec.rb +26 -0
  34. data/spec/unit/response/headers_spec.rb +23 -0
  35. data/spec/unit/response/html/class_methods/build_spec.rb +18 -0
  36. data/spec/unit/response/json/class_methods/build_spec.rb +18 -0
  37. data/spec/unit/response/last_modified_spec.rb +25 -0
  38. data/spec/unit/response/merge_headers_spec.rb +20 -0
  39. data/spec/unit/response/rack_array_spec.rb +15 -0
  40. data/spec/unit/response/redirect/class_methods/build_spec.rb +28 -0
  41. data/spec/unit/response/status_spec.rb +22 -0
  42. data/spec/unit/response/text/class_methods/build_spec.rb +18 -0
  43. data/spec/unit/response/to_rack_response_spec.rb +26 -0
  44. data/spec/unit/response/valid_predicate_spec.rb +37 -0
  45. data/spec/unit/response/with_body_spec.rb +17 -0
  46. data/spec/unit/response/with_headers_spec.rb +17 -0
  47. data/spec/unit/response/with_status_spec.rb +17 -0
  48. data/spec/unit/response/xml/class_methods/build_spec.rb +18 -0
  49. data/tasks/metrics/ci.rake +7 -0
  50. data/tasks/metrics/flay.rake +47 -0
  51. data/tasks/metrics/flog.rake +43 -0
  52. data/tasks/metrics/heckle.rake +208 -0
  53. data/tasks/metrics/metric_fu.rake +29 -0
  54. data/tasks/metrics/reek.rake +15 -0
  55. data/tasks/metrics/roodi.rake +15 -0
  56. data/tasks/metrics/yardstick.rake +23 -0
  57. data/tasks/spec.rake +45 -0
  58. data/tasks/yard.rake +9 -0
  59. metadata +187 -0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ /Gemfile.lock
2
+ /tmp
3
+ /.bundle
4
+ /vendor
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,16 @@
1
+ language: ruby
2
+ before_install: gem install bundler
3
+ script: bundle exec rake ci
4
+ rvm:
5
+ - 1.8.7
6
+ - 1.9.2
7
+ - 1.9.3
8
+ #- ruby-head Disabled while ffi does not build under ruby-head
9
+ - rbx-18mode
10
+ - rbx-19mode
11
+ - jruby-18mode
12
+ - jruby-19mode
13
+ - jruby-head
14
+ allowed_failures:
15
+ matrix:
16
+ - ree
data/Changelog.md ADDED
@@ -0,0 +1,3 @@
1
+ # v0.0.2 2013-05-21
2
+
3
+ * [change] Update to concord ~> 0.2.0
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'devtools', :git => 'https://github.com/datamapper/devtools.git'
6
+ eval File.read('Gemfile.devtools')
data/Gemfile.devtools ADDED
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ group :development do
4
+ gem 'rake', '~> 10.0.4'
5
+ gem 'rspec', '~> 2.13.0'
6
+ gem 'yard', '~> 0.8.6.1'
7
+ end
8
+
9
+ group :yard do
10
+ gem 'kramdown', '~> 1.0.1'
11
+ end
12
+
13
+ group :guard do
14
+ gem 'guard', '~> 1.8.0'
15
+ gem 'guard-bundler', '~> 1.0.0'
16
+ gem 'guard-rspec', '~> 2.5.4'
17
+
18
+ # file system change event handling
19
+ gem 'listen', '~> 1.0.2'
20
+ gem 'rb-fchange', '~> 0.0.6', :require => false
21
+ gem 'rb-fsevent', '~> 0.9.3', :require => false
22
+ gem 'rb-inotify', '~> 0.9.0', :require => false
23
+
24
+ # notification handling
25
+ gem 'libnotify', '~> 0.8.0', :require => false
26
+ gem 'rb-notifu', '~> 0.0.4', :require => false
27
+ gem 'terminal-notifier-guard', '~> 1.5.3', :require => false
28
+ end
29
+
30
+ group :metrics do
31
+ gem 'backports', '~> 3.3', '>= 3.3.0'
32
+ gem 'coveralls', '~> 0.6.6'
33
+ gem 'flay', '~> 2.2.0'
34
+ gem 'flog', '~> 4.0.0'
35
+ gem 'reek', '~> 1.3.1', :git => 'https://github.com/troessner/reek.git'
36
+ gem 'simplecov', '~> 0.7.1'
37
+ gem 'yardstick', '~> 0.9.6'
38
+
39
+ platforms :ruby_19 do
40
+ gem 'yard-spellcheck', '~> 0.1.5'
41
+ end
42
+
43
+ platforms :mri_19, :rbx do
44
+ gem 'mutant', '~> 0.2.20'
45
+ end
46
+
47
+ platforms :rbx do
48
+ gem 'pelusa', '~> 0.2.2'
49
+ end
50
+ end
51
+
52
+ group :benchmarks do
53
+ gem 'rbench', '~> 0.2.3'
54
+ end
55
+
56
+ platform :jruby do
57
+ group :jruby do
58
+ gem 'jruby-openssl', '~> 0.8.5'
59
+ end
60
+ end
data/Guardfile ADDED
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ guard :bundler do
4
+ watch('Gemfile')
5
+ end
6
+
7
+ guard :rspec do
8
+ # run all specs if the spec_helper or supporting files files are modified
9
+ watch('spec/spec_helper.rb') { 'spec' }
10
+ watch(%r{\Aspec/(?:lib|support|shared)/.+\.rb\z}) { 'spec' }
11
+
12
+ # run unit specs if associated lib code is modified
13
+ watch(%r{\Alib/(.+)\.rb\z}) { |m| Dir["spec/unit/#{m[1]}"] }
14
+ watch("lib/#{File.basename(File.expand_path('../', __FILE__))}.rb") { 'spec' }
15
+
16
+ # run a spec if it is modified
17
+ watch(%r{\Aspec/(?:unit|integration)/.+_spec\.rb\z})
18
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Markus Schirp
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.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ response
2
+ ========
3
+
4
+ [![Build Status](https://secure.travis-ci.org/mbj/response.png?branch=master)](http://travis-ci.org/mbj/response)
5
+ [![Dependency Status](https://gemnasium.com/mbj/response.png)](https://gemnasium.com/mbj/response)
6
+ [![Code Climate](https://codeclimate.com/github/mbj/response.png)](https://codeclimate.com/github/mbj/response)
7
+
8
+ Build HTTP responses in a functional style. Yeah it has support for rack.
9
+
10
+ Installation
11
+ ------------
12
+
13
+ Use git source `gem 'response', :git => 'https://github.com/mbj/response`
14
+
15
+ Examples
16
+ --------
17
+
18
+ MISSING. See specs and in code docs!
19
+
20
+ Credits
21
+ -------
22
+
23
+ * Markus Schirp [mbj](https://github.com/mbj)
24
+
25
+ Contributing
26
+ ------------
27
+
28
+ * Fork the project.
29
+ * Make your feature addition or bug fix.
30
+ * Add tests for it. This is important so I don't break it in a
31
+ future version unintentionally.
32
+ * Commit, do not mess with Rakefile or version
33
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
34
+ * Send me a pull request. Bonus points for topic branches.
35
+
36
+ License
37
+ -------
38
+
39
+ See `LICENSE` file.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'devtools'
2
+ Devtools.init_rake_tasks
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ * Find something more pretty than the #with_ prefix for changeing components
2
+ * Do not represent header with primitive hash anymore
@@ -0,0 +1,2 @@
1
+ ---
2
+ unit_test_timeout: 1.0
data/config/flay.yml ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ threshold: 16
3
+ total_score: 40
data/config/flog.yml ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ threshold: 8.4
data/config/mutant.yml ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ name: request
3
+ namespace: Response
data/config/reek.yml ADDED
@@ -0,0 +1,92 @@
1
+ ---
2
+ UncommunicativeParameterName:
3
+ accept: []
4
+ exclude: []
5
+ enabled: true
6
+ reject:
7
+ - !ruby/regexp /^.$/
8
+ - !ruby/regexp /[0-9]$/
9
+ - !ruby/regexp /[A-Z]/
10
+ LargeClass:
11
+ max_methods: 12 # Todo bring down to 10
12
+ exclude: []
13
+ enabled: true
14
+ max_instance_variables: 3
15
+ UncommunicativeMethodName:
16
+ accept: []
17
+ exclude: []
18
+ enabled: true
19
+ reject:
20
+ - !ruby/regexp /^[a-z]$/
21
+ - !ruby/regexp /[0-9]$/
22
+ - !ruby/regexp /[A-Z]/
23
+ LongParameterList:
24
+ max_params: 2
25
+ exclude:
26
+ - Response#self.build # 3 params
27
+ enabled: true
28
+ overrides: {}
29
+ FeatureEnvy:
30
+ exclude: []
31
+ enabled: true
32
+ ClassVariable:
33
+ exclude: []
34
+ enabled: true
35
+ BooleanParameter:
36
+ exclude: []
37
+ enabled: true
38
+ IrresponsibleModule:
39
+ exclude: []
40
+ enabled: true
41
+ UncommunicativeModuleName:
42
+ accept: []
43
+ exclude: []
44
+ enabled: true
45
+ reject:
46
+ - !ruby/regexp /^.$/
47
+ - !ruby/regexp /[0-9]$/
48
+ NestedIterators:
49
+ ignore_iterators: []
50
+ exclude: []
51
+ enabled: true
52
+ max_allowed_nesting: 1
53
+ LongMethod:
54
+ max_statements: 7 # TODO: decrease max_statements to 5 or less
55
+ exclude: []
56
+ enabled: true
57
+ Duplication:
58
+ allow_calls: []
59
+ exclude: []
60
+ enabled: true
61
+ max_calls: 1
62
+ UtilityFunction:
63
+ max_helper_calls: 1
64
+ exclude: []
65
+ enabled: true
66
+ Attribute:
67
+ exclude: []
68
+ enabled: false
69
+ UncommunicativeVariableName:
70
+ accept: []
71
+ exclude: []
72
+ enabled: true
73
+ reject:
74
+ - !ruby/regexp /^.$/
75
+ - !ruby/regexp /[0-9]$/
76
+ - !ruby/regexp /[A-Z]/
77
+ SimulatedPolymorphism:
78
+ exclude: []
79
+ enabled: true
80
+ max_ifs: 1
81
+ DataClump:
82
+ exclude: []
83
+ enabled: true
84
+ max_copies: 1
85
+ min_clump_size: 3
86
+ ControlCouple:
87
+ exclude: []
88
+ enabled: true
89
+ LongYieldList:
90
+ max_params: 1
91
+ exclude: []
92
+ enabled: true
data/config/roodi.yml ADDED
@@ -0,0 +1,18 @@
1
+ ---
2
+ AbcMetricMethodCheck: { score: 10.3 }
3
+ AssignmentInConditionalCheck: { }
4
+ CaseMissingElseCheck: { }
5
+ ClassLineCountCheck: { line_count: 293 }
6
+ ClassNameCheck: { pattern: !ruby/regexp '/\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/' }
7
+ ClassVariableCheck: { }
8
+ CyclomaticComplexityBlockCheck: { complexity: 2 }
9
+ CyclomaticComplexityMethodCheck: { complexity: 4 }
10
+ EmptyRescueBodyCheck: { }
11
+ ForLoopCheck: { }
12
+ # TODO: decrease line_count to 5 to 10
13
+ MethodLineCountCheck: { line_count: 14 }
14
+ MethodNameCheck: { pattern: !ruby/regexp '/\A(?:[a-z\d](?:_?[a-z\d])+[?!=]?|\[\]=?|==|<=>|[+*&|-])\z/' }
15
+ ModuleLineCountCheck: { line_count: 295 }
16
+ ModuleNameCheck: { pattern: !ruby/regexp '/\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/' }
17
+ # TODO: decrease parameter_count to 2 or less
18
+ ParameterNumberCheck: { parameter_count: 3 }
@@ -0,0 +1,2 @@
1
+ ---
2
+ threshold: 100
@@ -0,0 +1,36 @@
1
+ class Response
2
+ # HTML response
3
+ class HTML < self
4
+ HEADERS = IceNine.deep_freeze('Content-Type' => 'text/html; charset=UTF-8')
5
+
6
+ # Build html response with defaults
7
+ #
8
+ # @param [Object] body
9
+ # rack compatible body
10
+ #
11
+ # @return [Array]
12
+ # rack compatible response array
13
+ #
14
+ # @example
15
+ #
16
+ # # With defaults
17
+ # response = Response::HTML.build("<html><body>Hello</body></html>")
18
+ # response.status # => Response::Status::OK
19
+ # response.headers # => { 'Content-Type' => 'text/html; charset=UTF-8' }
20
+ # response.body # => "<html><body>Hello</body></html>"
21
+ #
22
+ # # With overriding defaults
23
+ # response = Response::HTML.build("<html><body>Hello</body></html>") do |response|
24
+ # response.with_status(Respnse::Status::NOT_FOUND)
25
+ # end
26
+ # response.status # => Response::Status::NOT_FOUND
27
+ # response.headers # => { 'Content-Type' => 'text/html; charset=UTF-8' }
28
+ # response.body # => "<html><body>Hello</body></html>"
29
+ #
30
+ # @api public
31
+ #
32
+ def self.build(body)
33
+ super(Status::OK, HEADERS, body)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ class Response
2
+ # JSON response
3
+ class JSON < self
4
+ HEADERS = IceNine.deep_freeze('Content-Type' => 'application/json; charset=UTF-8')
5
+
6
+ # Build JSON response with defaults
7
+ #
8
+ # @param [Object] body
9
+ # rack compatible body
10
+ #
11
+ # @return [Array]
12
+ # rack compatible response array
13
+ #
14
+ # @example
15
+ #
16
+ # # With defaults
17
+ # response = Response::JSON.build('{"foo":"bar"}')
18
+ # response.status # => Response::Status::OK
19
+ # response.headers # => { 'Content-Type' => 'application/json; charset=UTF-8' }
20
+ # response.body # => "{\"foo\":\"bar\"}"
21
+ #
22
+ # # With overriding defaults
23
+ # response = Response::HTML.build("<foo><bar>Hello</bar></foo>") do |response|
24
+ # response.with_status(Response::Status::NOT_FOUND)
25
+ # end
26
+ # response.status # => Response::Status::NOT_FOUND
27
+ # response.headers # => { 'Content-Type' => 'application/json; charset=UTF-8' }
28
+ # response.body # => "{\"foo\":\"bar\"}"
29
+ #
30
+ # @api public
31
+ #
32
+ def self.build(body)
33
+ super(Status::OK, HEADERS, body)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,52 @@
1
+ class Response
2
+ # Abstract redirect response
3
+ class Redirect < self
4
+ include AbstractType
5
+
6
+ # Build redirect response
7
+ #
8
+ # @param [String] location
9
+ # the location to redirect to
10
+ #
11
+ # @return [Array]
12
+ # rack compatible array
13
+ #
14
+ # @example
15
+ #
16
+ # # 302 response
17
+ # response = Response::Redirect::Found.build('http://example.com')
18
+ # response.status # => 302
19
+ # response.headers # => { "Location" => "http://example.com", "Content-Type" => "text/plain" }
20
+ # response.body # => "You are beeing redirected to: http://example.com"
21
+ #
22
+ # # 301 response
23
+ # response = Response::Redirect::Permanent.build('http://example.com')
24
+ # response.status # => 301
25
+ # response.headers # => { "Location" => "http://example.com", "Content-Type" => "text/plain" }
26
+ # response.body # => "You are beeing redirected to: http://example.com"
27
+ #
28
+ # # Overriding defaults
29
+ #
30
+ # response = Response::Redirect::Found.build('http://example.com') do |response|
31
+ # response.with_body("Redirection")
32
+ # end
33
+ #
34
+ # response[2] # => "Redirection"
35
+ #
36
+ # @api public
37
+ #
38
+ def self.build(location)
39
+ super(self::STATUS, {'Location' => location, 'Content-Type' => TEXT_PLAIN}, "You are beeing redirected to: #{location}")
40
+ end
41
+
42
+ # Response with default status code of 302
43
+ class Found < self
44
+ STATUS = Status::FOUND
45
+ end
46
+
47
+ # Response with default status code of 301
48
+ class Permanent < self
49
+ STATUS = Status::MOVED_PERMANENTLY
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,28 @@
1
+ class Response
2
+ # HTTP response status code with text
3
+ class Status
4
+ include Adamantium, Concord.new(:code, :text)
5
+
6
+ private_class_method :new
7
+
8
+ OK = new(200, 'OK' )
9
+ CREATED = new(201, 'Created' )
10
+ NOT_FOUND = new(404, 'Not Found' )
11
+ NOT_MODIFIED = new(304, 'Not Modified' )
12
+ FOUND = new(302, 'Found' )
13
+ MOVED_PERMANENTLY = new(301, 'Moved Permanently' )
14
+ BAD_REQUEST = new(400, 'Bad Request' )
15
+ NOT_AUTHORIZED = new(401, 'Not Authorized' )
16
+ FORBIDDEN = new(403, 'Forbidden' )
17
+ INTERNAL_SERVER_ERROR = new(500, 'Internal Server Error')
18
+
19
+ # Return status code
20
+ #
21
+ # @return [Fixnum]
22
+ #
23
+ # @api private
24
+ #
25
+ attr_reader :code
26
+
27
+ end # Status
28
+ end # Response
@@ -0,0 +1,37 @@
1
+ class Response
2
+ # TEXT response
3
+ class Text < self
4
+ HEADERS = IceNine.deep_freeze('Content-Type' => 'text/plain; charset=UTF-8')
5
+
6
+ # Build text response with defaults
7
+ #
8
+ # @param [Object] body
9
+ # rack compatible body
10
+ #
11
+ # @return [Array]
12
+ # rack compatible response array
13
+ #
14
+ # @example
15
+ #
16
+ # # With defaults
17
+ # response = Response::Text.build('foo')
18
+ # response.status # => Response::Status::OK
19
+ # response.headers # => { 'Content-Type' => 'text/plain; charset=UTF-8' }
20
+ # response.body # => "foo"
21
+ #
22
+ # # With overriding defaults
23
+ # response = Response::HTML.build('foo') do |response|
24
+ # response.with_status(Respnse::Status::NOT_FOUND)
25
+ # end
26
+ # response.status # => Response::Status::NOT_FOUND
27
+ # response.headers # => { 'Content-Type' => 'text/plain; charset=UTF-8' }
28
+ # response.body # => "foo"
29
+ #
30
+ # @api public
31
+ #
32
+ def self.build(body)
33
+ super(Status::OK, HEADERS, body)
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ class Response
2
+ # XML response
3
+ class XML < self
4
+ HEADERS = IceNine.deep_freeze('Content-Type' => 'application/xml; charset=UTF-8')
5
+
6
+ # Build xml response with defaults
7
+ #
8
+ # @param [Object] body
9
+ # rack compatible body
10
+ #
11
+ # @return [Array]
12
+ # rack compatible response array
13
+ #
14
+ # @example
15
+ #
16
+ # # With defaults
17
+ # response = Response::XML.build("<foo><bar>Hello</bar></foo>")
18
+ # response.status # => Response::Status::OK
19
+ # response.headers # => { 'Content-Type' => 'application/xml; charset=UTF-8' }
20
+ # response.body # => "<foo><bar>Hello</bar></foo>"
21
+ #
22
+ # # With overriding defaults
23
+ # response = Response::HTML.build("<foo><bar>Hello</bar></foo>") do |response|
24
+ # response.with_status(Response::Status::NOT_FOUND)
25
+ # end
26
+ # response.status # => Response::Status::NOT_FOUND
27
+ # response.headers # => { 'Content-Type' => 'application/xml; charset=UTF-8' }
28
+ # response.body # => "<foo><bar>Hello</bar></foo>"
29
+ #
30
+ # @api public
31
+ #
32
+ def self.build(body)
33
+ super(Status::OK, HEADERS, body)
34
+ end
35
+ end
36
+ end