crepe 0.0.1.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ module Crepe
2
+ module Middleware
3
+ # This middleware wraps boths sides of a request.
4
+ #
5
+ # Going in, it munges the Rack environment so that a HEAD request
6
+ # masquerades as a GET request by the time it hits a Crepe Endpoint. The
7
+ # Crepe request helper will know it's a HEAD request by referring to the
8
+ # `crepe.original_request_method` environment value.
9
+ #
10
+ # Going out, it ensures an empty response body.
11
+ class Head
12
+
13
+ def initialize app
14
+ @app = app
15
+ end
16
+
17
+ def call env
18
+ if env['REQUEST_METHOD'] == 'HEAD'
19
+ env['crepe.original_request_method'] = 'HEAD'
20
+ env['REQUEST_METHOD'] = 'GET'
21
+ status, headers, _ = @app.call env
22
+ [status, headers, []]
23
+ else
24
+ @app.call env
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ module Crepe
2
+ module Middleware
3
+ # This middleware provides intelligent defaults for response status codes
4
+ # depending on the HTTP verb:
5
+ #
6
+ # - POST will provide 201 Created.
7
+ #
8
+ # - DELETE will provide 204 No Content (and clear the response body).
9
+ class RestfulStatus
10
+
11
+ def initialize app
12
+ @app = app
13
+ end
14
+
15
+ def call env
16
+ status, headers, body = @app.call env
17
+
18
+ if status == 200
19
+ case env['REQUEST_METHOD']
20
+ when 'POST'
21
+ status = 201
22
+ when 'DELETE'
23
+ status = 204
24
+ body = []
25
+ end
26
+ end
27
+
28
+ [status, headers, body]
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,74 @@
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+ require 'crepe/util'
3
+
4
+ module Crepe
5
+ #--
6
+ # Based on https://github.com/rails/strong_parameters, provides a security
7
+ # proxy object for submitted parameters.
8
+ #++
9
+ class Params < BasicObject
10
+
11
+ instance_methods.grep(/^[^_]/).each { |m| undef_method m }
12
+
13
+ # Raised when a required parameter is missing (see Crepe::Params#require).
14
+ class Missing < ::IndexError
15
+
16
+ attr_reader :key
17
+
18
+ def initialize key
19
+ @key = key
20
+ super "Missing parameter: #{key}"
21
+ end
22
+
23
+ end
24
+
25
+ # Raised when an unpermitted parameter is found (see Crepe::Params#permit).
26
+ class Invalid < ::StandardError
27
+
28
+ attr_reader :keys
29
+
30
+ def initialize keys
31
+ @keys = keys
32
+ super "Invalid parameter(s): #{keys.join ', '}"
33
+ end
34
+
35
+ end
36
+
37
+ def initialize params = {}
38
+ @params = ::HashWithIndifferentAccess.new params
39
+ ::Crepe::Util.deep_freeze @params
40
+ @permitted = false
41
+ end
42
+
43
+ def require required_key
44
+ fetch(required_key) { raise Missing, required_key }
45
+ end
46
+
47
+ def permit *secure_keys
48
+ insecure_keys = keys - secure_keys.map(&:to_s)
49
+ raise Invalid, insecure_keys unless insecure_keys.empty?
50
+ @permitted = true
51
+ self
52
+ end
53
+
54
+ def permitted?
55
+ @permitted
56
+ end
57
+
58
+ def dup
59
+ @params.dup
60
+ end
61
+
62
+ def respond_to? method_name, include_private = false
63
+ [:require, :permit, :permitted?].include? method_name or super
64
+ end
65
+
66
+ private
67
+
68
+ def method_missing method_name, *args, &block
69
+ value = @params.send method_name, *args, &block
70
+ value.is_a?(::Hash) ? ::Crepe::Params.new(value) : value
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,73 @@
1
+ require 'active_support/core_ext/object/duplicable'
2
+
3
+ module Crepe
4
+ module Util
5
+
6
+ autoload :HashStack, 'crepe/util/hash_stack'
7
+ autoload :ChainedInclude, 'crepe/util/chained_include'
8
+
9
+ # Deeply duplicates values in the object passed in. If the object
10
+ # is a Hash or Array, it recursively dups the object's values.
11
+ #
12
+ # Active Support's deep_dup does not dup array contents.
13
+ def deep_dup object
14
+ object = object.dup if object.duplicable?
15
+
16
+ case object
17
+ when Hash then object.each { |k, v| object[k] = deep_dup v }
18
+ when Array then object.map! { |o| deep_dup o }
19
+ end
20
+
21
+ object
22
+ end
23
+
24
+ # See `deeper_merge!`: returns a copy of the original hash, rather
25
+ # than merging it in place.
26
+ def deeper_merge hash, other_hash
27
+ deeper_merge! hash.dup, other_hash
28
+ end
29
+
30
+ # Deeply merges the first hash with the second hash, concatenating
31
+ # any array values that are shared across keys.
32
+ def deeper_merge! hash, other_hash
33
+ other_hash.each do |key, value|
34
+ if hash[key].is_a?(Hash) && value.is_a?(Hash)
35
+ hash[key] = deeper_merge hash[key], value
36
+ elsif hash[key].is_a?(Array) && value.is_a?(Array)
37
+ hash[key] += value
38
+ else
39
+ hash[key] = value
40
+ end
41
+ end
42
+
43
+ hash
44
+ end
45
+
46
+ # Recursively freezes all keys and values.
47
+ def deep_freeze hash
48
+ hash.each do |key, value|
49
+ case value
50
+ when Hash then deep_freeze value
51
+ when Array then value.each { |v| deep_freeze v }
52
+ else value.freeze
53
+ end
54
+ end
55
+ hash.freeze
56
+ end
57
+
58
+ def normalize_path path
59
+ normalize_path! path.dup
60
+ end
61
+
62
+ def normalize_path! path
63
+ path.squeeze! '/'
64
+ path.sub! %r{/+\z}, ''
65
+ path.sub! %r{/([.?])}, '\1'
66
+ path.replace '/' if path.empty?
67
+ path
68
+ end
69
+
70
+ extend self
71
+
72
+ end
73
+ end
@@ -0,0 +1,78 @@
1
+ module Crepe
2
+ module Util
3
+ # Forwards all future includes to objects that have already been
4
+ # extended by (or have included) the parent module.
5
+ #
6
+ # Default Ruby behavior:
7
+ #
8
+ # # A module is defined...
9
+ # module A
10
+ # end
11
+ #
12
+ # # ...and included in a class.
13
+ # class B
14
+ # include Module A
15
+ # end
16
+ #
17
+ # # Given another module...
18
+ # module C
19
+ # def c
20
+ # end
21
+ # end
22
+ #
23
+ # # ...included in the first...
24
+ # module A
25
+ # include Module C
26
+ # end
27
+ #
28
+ # # ...the class will not have access to its methods.
29
+ # B.new.c # NoMethodError: undefined method `c' for #<B>
30
+ #
31
+ # To prevent the above error, the original module could have been
32
+ # extended with ChainedInclude:
33
+ #
34
+ # module A
35
+ # extend ChainedInclude
36
+ # end
37
+ # class B
38
+ # include Module A
39
+ # end
40
+ # module C
41
+ # def c
42
+ # end
43
+ # end
44
+ # module A
45
+ # include Module C
46
+ # end
47
+ # B.new.c # => nil
48
+ module ChainedInclude
49
+
50
+ private
51
+
52
+ def include mod
53
+ super
54
+ extending.each { |object| object.extend mod }
55
+ included_by.each { |base| base.__send__ :include, mod }
56
+ end
57
+
58
+ def extended object
59
+ super
60
+ extending << object
61
+ end
62
+
63
+ def included base
64
+ super
65
+ included_by << base
66
+ end
67
+
68
+ def extending
69
+ @_extending ||= []
70
+ end
71
+
72
+ def included_by
73
+ @_included_by ||= []
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,57 @@
1
+ require 'active_support/core_ext/array/wrap'
2
+ require 'active_support/core_ext/module/delegation'
3
+
4
+ module Crepe
5
+ module Util
6
+ # A {Hash}-like object that scopes state changes using an underlying stack.
7
+ class HashStack
8
+
9
+ def initialize first = {}
10
+ @stack = Array.wrap first
11
+ end
12
+
13
+ delegate :pop, :push, :<<,
14
+ to: :stack
15
+
16
+ def top
17
+ stack.last
18
+ end
19
+
20
+ delegate :[]=, :delete,
21
+ to: :top
22
+
23
+ def key? key
24
+ stack.any? { |frame| frame.key? key }
25
+ end
26
+
27
+ def [] key
28
+ found_at = stack.reverse.detect { |frame| frame.key? key }
29
+ found_at && found_at[key]
30
+ end
31
+
32
+ def all key
33
+ stack.map { |frame| frame[key] }.flatten 1
34
+ end
35
+
36
+ def with frame = {}
37
+ self << frame
38
+ yield
39
+ pop
40
+ end
41
+
42
+ def to_hash
43
+ stack.inject({}, &:merge)
44
+ end
45
+ alias_method :to_h, :to_hash
46
+
47
+ def dup
48
+ self.class.new Util.deep_dup stack
49
+ end
50
+
51
+ attr_reader :stack
52
+ private :stack
53
+
54
+ end
55
+ end
56
+ end
57
+
@@ -0,0 +1,10 @@
1
+ module Crepe
2
+
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ PATCH = 1
6
+ PRE = 'pre'
7
+
8
+ VERSION = [MAJOR, MINOR, PATCH, PRE].compact.join '.'
9
+
10
+ end
metadata ADDED
@@ -0,0 +1,207 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: crepe
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.pre
5
+ platform: ruby
6
+ authors:
7
+ - Stephen Celis
8
+ - Evan Owen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: 3.2.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ version: 3.2.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: rack
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 1.5.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ version: 1.5.0
42
+ - !ruby/object:Gem::Dependency
43
+ name: rack-mount
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: 0.8.0
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: 0.8.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: cane
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: 2.3.0
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 2.3.0
70
+ - !ruby/object:Gem::Dependency
71
+ name: multi_json
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 1.6.0
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ~>
82
+ - !ruby/object:Gem::Version
83
+ version: 1.6.0
84
+ - !ruby/object:Gem::Dependency
85
+ name: multi_xml
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ version: 0.5.0
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ~>
96
+ - !ruby/object:Gem::Version
97
+ version: 0.5.0
98
+ - !ruby/object:Gem::Dependency
99
+ name: rake
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ~>
103
+ - !ruby/object:Gem::Version
104
+ version: 10.0.0
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ~>
110
+ - !ruby/object:Gem::Version
111
+ version: 10.0.0
112
+ - !ruby/object:Gem::Dependency
113
+ name: rspec
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ~>
117
+ - !ruby/object:Gem::Version
118
+ version: 2.13.0
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: 2.13.0
126
+ - !ruby/object:Gem::Dependency
127
+ name: rack-test
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ~>
131
+ - !ruby/object:Gem::Version
132
+ version: 0.6.0
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ~>
138
+ - !ruby/object:Gem::Version
139
+ version: 0.6.0
140
+ - !ruby/object:Gem::Dependency
141
+ name: tilt
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ~>
145
+ - !ruby/object:Gem::Version
146
+ version: 1.3.0
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ~>
152
+ - !ruby/object:Gem::Version
153
+ version: 1.3.0
154
+ description: |
155
+ Rack-based API framework
156
+ email:
157
+ - stephen@stephencelis.com
158
+ - kainosnoema@gmail.com
159
+ executables: []
160
+ extensions: []
161
+ extra_rdoc_files: []
162
+ files:
163
+ - lib/crepe/api.rb
164
+ - lib/crepe/endpoint/filter/acceptance.rb
165
+ - lib/crepe/endpoint/filter/parser.rb
166
+ - lib/crepe/endpoint/filter.rb
167
+ - lib/crepe/endpoint/renderer/base.rb
168
+ - lib/crepe/endpoint/renderer/simple.rb
169
+ - lib/crepe/endpoint/renderer/tilt.rb
170
+ - lib/crepe/endpoint/renderer.rb
171
+ - lib/crepe/endpoint/request.rb
172
+ - lib/crepe/endpoint.rb
173
+ - lib/crepe/middleware/content_negotiation.rb
174
+ - lib/crepe/middleware/head.rb
175
+ - lib/crepe/middleware/restful_status.rb
176
+ - lib/crepe/middleware.rb
177
+ - lib/crepe/params.rb
178
+ - lib/crepe/util/chained_include.rb
179
+ - lib/crepe/util/hash_stack.rb
180
+ - lib/crepe/util.rb
181
+ - lib/crepe/version.rb
182
+ - lib/crepe.rb
183
+ homepage: https://github.com/stephencelis/crepe
184
+ licenses:
185
+ - MIT
186
+ metadata: {}
187
+ post_install_message:
188
+ rdoc_options: []
189
+ require_paths:
190
+ - lib
191
+ required_ruby_version: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - '>='
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ required_rubygems_version: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - '>'
199
+ - !ruby/object:Gem::Version
200
+ version: 1.3.1
201
+ requirements: []
202
+ rubyforge_project:
203
+ rubygems_version: 2.0.2
204
+ signing_key:
205
+ specification_version: 4
206
+ summary: Rack-based API framework
207
+ test_files: []