crepe 0.0.1.pre

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.
@@ -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: []