roda-rest_api 1.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7f98977e20fcce7bdf02b180031b03f0cbebfa08
4
+ data.tar.gz: c5290bbd379c6dbd9fc9ea229b918a0e5a28e4f7
5
+ SHA512:
6
+ metadata.gz: eade3e6d217f63b668a10dd1c9625435a644f3b21fbb09979854ce0ebbd988bb6752f78edba4d421f699a26aa2ec47be0c8b391aa259c9198237b148ae163bc0
7
+ data.tar.gz: d284cc3570aa55caf3ac9605919169a8a0e1d00daf69d851b0a067bc92c8fd9423baa9a966551d01b4816f7a38fb6c63776ee796191197415525cc20b1a18dcc
@@ -0,0 +1,168 @@
1
+ class Roda
2
+ module RodaPlugins
3
+
4
+ module RestApi
5
+
6
+ def self.load_dependencies(app, _opts = {})
7
+ app.plugin :all_verbs
8
+ app.plugin :symbol_matchers
9
+ app.plugin :header_matchers
10
+ end
11
+
12
+ class Resource
13
+
14
+ APPLICATION_JSON = 'application/json'.freeze
15
+
16
+ attr_reader :singleton, :content_type
17
+
18
+ def initialize(request, options={})
19
+ @request = request
20
+ @singleton = options.delete(:singleton) || false
21
+ @primary_key = options.delete(:primary_key) || "id"
22
+ @content_type = options.delete(:content_type) || APPLICATION_JSON
23
+ end
24
+
25
+ def list(&block)
26
+ @list = block if block
27
+ @list || ->(_){raise NotImplementedError, "list"}
28
+ end
29
+
30
+ def one(&block)
31
+ @one = block if block
32
+ @one || ->(_){raise NotImplementedError, "one"}
33
+ end
34
+
35
+ def save(&block)
36
+ @save = block if block
37
+ @save || ->(_){raise NotImplementedError, "save"}
38
+ end
39
+
40
+ def delete(&block)
41
+ @delete = block if block
42
+ @delete || ->(_){raise NotImplementedError, "delete"}
43
+ end
44
+
45
+ def serialize(&block)
46
+ @serialize = block if block
47
+ @serialize || ->(obj){obj.is_a?(String) ? obj : obj.send(:to_json)}
48
+ end
49
+
50
+ def routes(*routes)
51
+ @routes = routes
52
+ end
53
+
54
+ def routes!
55
+ @routes = %i{ index show create update destroy edit new } unless @routes
56
+ @routes.delete :index if @singleton
57
+ @routes.each { |route| @request.send(route) }
58
+ end
59
+
60
+ def perform(method, id = nil)
61
+ args = method === :save ? JSON.parse(@request.body) : @request.GET
62
+ args.merge!(@primary_key => id) if id
63
+ self.send(method).call(args) rescue @request.response.status = 404
64
+ end
65
+
66
+ end
67
+
68
+ module RequestMethods
69
+
70
+ def api(options={}, &block)
71
+ path = options.delete(:path) || 'api'
72
+ subdomain = options.delete(:subdomain)
73
+ options.merge!(host: /\A#{Regexp.escape(subdomain)}\./) if subdomain
74
+ on([path, true], options, &block)
75
+ end
76
+
77
+ def version(version, &block)
78
+ on("v#{version}", &block)
79
+ end
80
+
81
+ def resource(name, options={})
82
+ @resource = Resource.new(self, options)
83
+ on(name.to_s, options) do
84
+ yield @resource
85
+ @resource.routes!
86
+ response.status = 404
87
+ end
88
+ end
89
+
90
+ def index(options={}, &block)
91
+ block ||= ->{ @resource.perform(:list) }
92
+ get(['', true], options, &block)
93
+ end
94
+
95
+ def show(options={}, &block)
96
+ block ||= default_block(:one)
97
+ get(path, options, &block)
98
+ end
99
+
100
+ def create(options={}, &block)
101
+ block ||= ->{@resource.perform(:save)}
102
+ post(["", true], options) do
103
+ response.status = 201
104
+ block.call(*captures) if block
105
+ end
106
+ end
107
+
108
+ def update(options={}, &block)
109
+ block ||= default_block(:save)
110
+ options.merge!(method: [:put, :patch])
111
+ is(path, options, &block)
112
+ end
113
+
114
+ def destroy(options={}, &block)
115
+ block ||= default_block(:delete)
116
+ delete(path, options) do
117
+ response.status = 204
118
+ block.call(*captures) if block
119
+ end
120
+ end
121
+
122
+ def edit(options={}, &block)
123
+ block ||= default_block(:one)
124
+ get(path("edit"), options, &block)
125
+ end
126
+
127
+ def new(options={}, &block)
128
+ block ||= ->{@resource.perform(:one, "new")}
129
+ get("new", options, &block)
130
+ end
131
+
132
+ private
133
+
134
+ def path(path=nil)
135
+ if @resource.singleton
136
+ path = ["", true] unless path
137
+ else
138
+ path = [":d", path].compact.join("/")
139
+ end
140
+ path
141
+ end
142
+
143
+ def default_block(method)
144
+ if @resource.singleton
145
+ ->(){@resource.perform(method)}
146
+ else
147
+ ->(id){@resource.perform(method, id)}
148
+ end
149
+ end
150
+
151
+ CONTENT_TYPE = 'Content-Type'.freeze
152
+
153
+ def block_result_body(result)
154
+ if result && @resource
155
+ response[CONTENT_TYPE] = @resource.content_type
156
+ @resource.serialize.call(result)
157
+ else
158
+ super
159
+ end
160
+ end
161
+
162
+ end
163
+ end
164
+
165
+ register_plugin(:rest_api, RestApi)
166
+
167
+ end
168
+ end
@@ -0,0 +1,6 @@
1
+ require 'roda'
2
+ require 'roda/plugins/rest_api'
3
+
4
+ class Roda
5
+ plugin :rest_api
6
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: roda-rest_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Michel Benevento
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: roda
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A Roda plugin for RESTful APIs
56
+ email: michelbenevento@yahoo.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - lib/roda/plugins/rest_api.rb
62
+ - lib/roda/rest_api.rb
63
+ homepage: http://github.com/beno/roda-rest_api
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.4.2
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: REST APIs with Roda
87
+ test_files: []