rest_framework 0.0.1 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ae8173bd8209fe5250ec9fe3a749d41d46307f7948d1c7597921ab5b4d2cae2
4
- data.tar.gz: 3ca1aa88dbde70ad327a65778bfa7e2a90499111dbf6e16a9d084aba2df42328
3
+ metadata.gz: 5a70372b29a6a1f71c62ecfe54f87836c185986e0786be23c73d8da52c73e3d3
4
+ data.tar.gz: fa48c80ce2d183f31c3e9791a454462fd157f803bd3f77f620ebad13bb9b86a2
5
5
  SHA512:
6
- metadata.gz: bd56096773684dc55324b6a8d3fed2a7d214201fd9ac516862a24a111ecedcf70cebf20b61ff264f11a921d67e9a057da4a8b1c2d4c498d07bb042401993e5e3
7
- data.tar.gz: 2f9f5b01fa4a956f0047307ed0f9b7523607ad6487fa5f8fa15d9895b7ff814703c048e5a7a0261fad35f11b96f3078641e8b9dd9e897bdbbc15b36c775c084e
6
+ metadata.gz: 4c7819ea220f5a41890320d5f7c4667d9989d9a23a46c6d9e53b4c8fe558f187cbfa094616ade0013b2ed8a28732024403d416449589167d759eaa8f0df432b0
7
+ data.tar.gz: cf92ba584de58531b31ed33a1855270324559a4484c29a4ea953e4b2093080db3923e1ded3be6fedac867985febf11dbdfaf07600879b02ff6a17f5b87cef473
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # REST Framework
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/rest_framework.svg)](https://badge.fury.io/rb/rest_framework)
4
+ [![Build Status](https://travis-ci.org/gregschmit/rails-rest-framework.svg?branch=master)](https://travis-ci.org/gregschmit/rails-rest-framework)
5
+
3
6
  REST Framework helps you build awesome APIs in Ruby on Rails.
4
7
 
5
8
  **The Problem**: Building controllers for APIs usually involves writing a lot of redundant CRUD
@@ -65,13 +68,13 @@ end
65
68
  ```
66
69
 
67
70
  Note that you can also override `get_model` and `get_recordset` instance methods to override the API
68
- behavior based on each request.
71
+ behavior dynamically per-request.
69
72
 
70
73
  ### Routing
71
74
 
72
75
  You can use Rails' `resource`/`resources` routers to route your API, however if you want
73
- `@extra_actions`/`@extra_member_actions` to be routed automatically, then you can use the
74
- `rest_resource`/`rest_resources` routers provided by this gem. You can also use `rest_root` to route
76
+ `@extra_actions` / `@extra_member_actions` to be routed automatically, then you can use the
77
+ `rest_resource` / `rest_resources` routers provided by this gem. You can also use `rest_root` to route
75
78
  the root of your API:
76
79
 
77
80
  ```
@@ -0,0 +1,38 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title><%= @title %></title>
5
+ <%= render partial: 'rest_framework/head' %>
6
+ </head>
7
+
8
+ <body>
9
+ <div class="bg-dark">
10
+ <div class="w-100 m-0 p-0" style="height: .3em; background-color: #a00;"></div>
11
+ <nav class="navbar navbar-dark bg-dark">
12
+ <div class="container">
13
+ <span class="navbar-brand p-0">
14
+ <h1 class="text-light font-weight-light m-0 p-0" style="font-size: 1em"><%= @template_logo_text %></h1>
15
+ </span>
16
+ </div>
17
+ </nav>
18
+ </div>
19
+ <div class="container py-3">
20
+ <div class="container">
21
+ <div class="row">
22
+ <h1><%= @title %></h1>
23
+ </div>
24
+ <hr/>
25
+ <div class="row">
26
+ <h2>Payload</h2><br>
27
+ <div><pre><%= JSON.pretty_generate(JSON.parse(@serialized_payload)) unless @serialized_payload.blank? %></pre></div>
28
+ </div>
29
+ <% unless @routes.blank? %>
30
+ <div class="row">
31
+ <h2>Routes</h2>
32
+ <%= render partial: 'rest_framework/routes' %>
33
+ </div>
34
+ <% end %>
35
+ </div>
36
+ </div>
37
+ </body>
38
+ </html>
@@ -0,0 +1,19 @@
1
+ <meta charset="utf-8">
2
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
3
+ <%= csrf_meta_tags %>
4
+ <%= csp_meta_tag rescue nil %>
5
+
6
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
7
+ <style>
8
+ h1,h2,h3,h4,h5,h6 { width: 100%; }
9
+ h1 { font-size: 2rem; }
10
+ h2 { font-size: 1.7rem; }
11
+ h3 { font-size: 1.5rem; }
12
+ h4 { font-size: 1.3rem; }
13
+ h5 { font-size: 1.1rem; }
14
+ h6 { font-size: 1rem; }
15
+ </style>
16
+
17
+ <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
18
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
19
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
@@ -0,0 +1,18 @@
1
+ <table class="table">
2
+ <thead>
3
+ <tr>
4
+ <th scope="col">Verb</th>
5
+ <th scope="col">Path</th>
6
+ <th scope="col">Action</th>
7
+ </tr>
8
+ </thead>
9
+ <tbody>
10
+ <% @routes.each do |r| %>
11
+ <tr>
12
+ <td><%= r[:verb] %></td>
13
+ <td><%= r[:path] %></td>
14
+ <td><%= r[:action] %></td>
15
+ </tr>
16
+ <% end %>
17
+ </tbody>
18
+ </table>
@@ -2,5 +2,6 @@ module RESTFramework
2
2
  end
3
3
 
4
4
  require_relative "rest_framework/controllers"
5
+ require_relative "rest_framework/engine"
5
6
  require_relative "rest_framework/routers"
6
7
  require_relative "rest_framework/version"
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.7
@@ -2,7 +2,6 @@ module RESTFramework
2
2
 
3
3
  # This module provides helpers for mixin `ClassMethods` submodules.
4
4
  module ClassMethodHelpers
5
-
6
5
  # This helper assists in providing reader interfaces for mixin properties.
7
6
  def _restframework_attr_reader(property, default: nil)
8
7
  method = <<~RUBY
@@ -22,9 +21,8 @@ module RESTFramework
22
21
  # is defined.
23
22
  module BaseControllerMixin
24
23
  # Default action for API root.
25
- # TODO: use api_response and show sub-routes.
26
24
  def root
27
- render inline: "This is the root of your awesome API!"
25
+ api_response({message: "This is the root of your awesome API!"})
28
26
  end
29
27
 
30
28
  protected
@@ -32,27 +30,25 @@ module RESTFramework
32
30
  module ClassMethods
33
31
  extend ClassMethodHelpers
34
32
 
35
- # Interface for getting class-level instance/class variables.
33
+ # Interface for getting class-level instance/class variables. Note: we check if they are
34
+ # defined first rather than rescuing NameError to prevent uninitialized variable warnings.
36
35
  private def _restframework_try_class_level_variable_get(name, default: nil)
37
- begin
38
- v = instance_variable_get("@#{name}")
36
+ instance_variable = "@#{name}"
37
+ if self.instance_variable_defined?(instance_variable)
38
+ v = self.instance_variable_get(instance_variable)
39
39
  return v unless v.nil?
40
- rescue NameError
41
40
  end
42
- begin
43
- v = class_variable_get("@@#{name}")
41
+ class_variable = "@@#{name}"
42
+ if self.class_variable_defined?(class_variable)
43
+ v = self.class_variable_get(class_variable)
44
44
  return v unless v.nil?
45
- rescue NameError
46
45
  end
47
46
  return default
48
47
  end
49
48
 
50
- # Interface for registering exceptions handlers.
51
- # private def _restframework_register_exception_handlers
52
- # rescue_from
53
- # end
54
-
49
+ _restframework_attr_reader(:singleton_controller)
55
50
  _restframework_attr_reader(:extra_actions, default: {})
51
+ _restframework_attr_reader(:template_logo_text, default: 'Rails REST Framework')
56
52
 
57
53
  def skip_actions(skip_undefined: true)
58
54
  # first, skip explicitly skipped actions
@@ -73,11 +69,54 @@ module RESTFramework
73
69
  base.extend ClassMethods
74
70
  end
75
71
 
72
+ def _get_routes
73
+ begin
74
+ formatter = ActionDispatch::Routing::ConsoleFormatter::Sheet
75
+ rescue NameError
76
+ formatter = ActionDispatch::Routing::ConsoleFormatter
77
+ end
78
+ return ActionDispatch::Routing::RoutesInspector.new(Rails.application.routes.routes).format(
79
+ formatter.new
80
+ ).lines[1..].map { |r| r.split.last(3) }.map { |r|
81
+ {verb: r[0], path: r[1], action: r[2]}
82
+ }.select { |r| r[:path].start_with?(request.path) }
83
+ end
84
+
76
85
  # Helper alias for `respond_to`/`render`, and replace nil responses with blank ones.
77
- def api_response(value, **kwargs)
86
+ def api_response(payload, html_kwargs: nil, json_kwargs: nil, **kwargs)
87
+ html_kwargs ||= {}
88
+ json_kwargs ||= {}
89
+
90
+ # serialize the payload if it's not blank
91
+ if payload.blank?
92
+ serialized_payload = ''
93
+ else
94
+ if self.respond_to?(:get_model_serializer_config, true)
95
+ serialized_payload = payload.to_json(self.get_model_serializer_config)
96
+ else
97
+ serialized_payload = payload.to_json
98
+ end
99
+ end
100
+
78
101
  respond_to do |format|
79
- format.html
80
- format.json { render json: value || '', **kwargs }
102
+ format.html {
103
+ kwargs = kwargs.merge(html_kwargs)
104
+ @template_logo_text ||= self.class.template_logo_text
105
+ @title ||= self.controller_name.camelize
106
+ @routes ||= self._get_routes
107
+ @payload = payload
108
+ @serialized_payload = serialized_payload
109
+ begin
110
+ render(**kwargs)
111
+ rescue ActionView::MissingTemplate # fallback to rest_framework default view
112
+ kwargs[:template] = "rest_framework/default"
113
+ end
114
+ render(**kwargs)
115
+ }
116
+ format.json {
117
+ kwargs = kwargs.merge(json_kwargs)
118
+ render(json: serialized_payload || '', **kwargs)
119
+ }
81
120
  end
82
121
  end
83
122
  end
@@ -21,7 +21,6 @@ module RESTFramework
21
21
 
22
22
  _restframework_attr_reader(:model)
23
23
  _restframework_attr_reader(:recordset)
24
- _restframework_attr_reader(:singleton_controller)
25
24
 
26
25
  _restframework_attr_reader(:fields)
27
26
  _restframework_attr_reader(:list_fields)
@@ -51,7 +50,7 @@ module RESTFramework
51
50
 
52
51
  # Get a list of fields for the current action.
53
52
  def get_fields
54
- return @fields if @fields
53
+ return @fields if instance_variable_defined?(:@fields) && @fields
55
54
 
56
55
  # index action should use list_fields
57
56
  name = (action_name == 'index') ? 'list' : action_name
@@ -60,9 +59,8 @@ module RESTFramework
60
59
  @fields = self.class.send("#{name}_fields")
61
60
  rescue NameError
62
61
  end
63
- @fields ||= self.class.fields || []
64
62
 
65
- return @fields
63
+ return @fields ||= self.class.fields || []
66
64
  end
67
65
 
68
66
  # Get a configuration passable to `as_json` for the model.
@@ -113,7 +111,7 @@ module RESTFramework
113
111
 
114
112
  # Internal interface for get_model, protecting against infinite recursion with get_recordset.
115
113
  def _get_model(from_internal_get_recordset: false)
116
- return @model if @model
114
+ return @model if instance_variable_defined?(:@model) && @model
117
115
  return self.class.model if self.class.model
118
116
  unless from_internal_get_recordset # prevent infinite recursion
119
117
  recordset = self._get_recordset(from_internal_get_model: true)
@@ -128,7 +126,7 @@ module RESTFramework
128
126
 
129
127
  # Internal interface for get_recordset, protecting against infinite recursion with get_model.
130
128
  def _get_recordset(from_internal_get_model: false)
131
- return @recordset if @recordset
129
+ return @recordset if instance_variable_defined?(:@recordset) && @recordset
132
130
  return self.class.recordset if self.class.recordset
133
131
  unless from_internal_get_model # prevent infinite recursion
134
132
  model = self._get_model(from_internal_get_recordset: true)
@@ -152,14 +150,14 @@ module RESTFramework
152
150
  # TODO: pagination classes like Django
153
151
  def index
154
152
  @records = self.get_filtered_recordset
155
- api_response(@records, **self.get_model_serializer_config)
153
+ api_response(@records)
156
154
  end
157
155
  end
158
156
 
159
157
  module ShowModelMixin
160
158
  def show
161
159
  @record = self.get_record
162
- api_response(@record, **self.get_model_serializer_config)
160
+ api_response(@record)
163
161
  end
164
162
  end
165
163
 
@@ -170,7 +168,7 @@ module RESTFramework
170
168
  rescue ActiveRecord::RecordInvalid => e
171
169
  api_response(e.record.messages, status: 400)
172
170
  end
173
- api_response(@record, **self.get_model_serializer_config)
171
+ api_response(@record)
174
172
  end
175
173
  end
176
174
 
@@ -180,7 +178,7 @@ module RESTFramework
180
178
  if @record
181
179
  @record.attributes(self.get_update_params)
182
180
  @record.save!
183
- api_response(@record, **self.get_model_serializer_config)
181
+ api_response(@record)
184
182
  else
185
183
  api_response({detail: "Record not found."}, status: 404)
186
184
  end
@@ -0,0 +1,2 @@
1
+ class RESTFramework::Engine < ::Rails::Engine
2
+ end
@@ -25,10 +25,10 @@ module ActionDispatch::Routing
25
25
 
26
26
  # convert class name to class
27
27
  begin
28
- controller = mod.const_get(name, false)
28
+ controller = mod.const_get(name)
29
29
  rescue NameError
30
30
  if fallback_reverse_pluralization
31
- controller = mod.const_get(name_reverse, false)
31
+ controller = mod.const_get(name_reverse)
32
32
  else
33
33
  raise
34
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest_framework
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregory N. Schmit
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-17 00:00:00.000000000 Z
11
+ date: 2020-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -33,11 +33,16 @@ extra_rdoc_files: []
33
33
  files:
34
34
  - LICENSE
35
35
  - README.md
36
+ - app/views/layouts/rest_framework.html.erb
37
+ - app/views/rest_framework/_head.html.erb
38
+ - app/views/rest_framework/_routes.html.erb
39
+ - app/views/rest_framework/default.html.erb
36
40
  - lib/rest_framework.rb
37
41
  - lib/rest_framework/VERSION_STAMP
38
42
  - lib/rest_framework/controllers.rb
39
43
  - lib/rest_framework/controllers/base.rb
40
44
  - lib/rest_framework/controllers/models.rb
45
+ - lib/rest_framework/engine.rb
41
46
  - lib/rest_framework/routers.rb
42
47
  - lib/rest_framework/version.rb
43
48
  homepage: https://github.com/gregschmit/rails-rest-framework
@@ -50,6 +55,7 @@ post_install_message:
50
55
  rdoc_options: []
51
56
  require_paths:
52
57
  - lib
58
+ - app
53
59
  required_ruby_version: !ruby/object:Gem::Requirement
54
60
  requirements:
55
61
  - - ">="