shaf 1.5.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/iana_link_relations.csv.gz +0 -0
  5. data/lib/shaf.rb +6 -0
  6. data/lib/shaf/alps/attribute_serializer.rb +41 -0
  7. data/lib/shaf/alps/json_serializer.rb +50 -0
  8. data/lib/shaf/alps/relation_serializer.rb +70 -0
  9. data/lib/shaf/api_doc/link_relations.rb +77 -0
  10. data/lib/shaf/app.rb +12 -5
  11. data/lib/shaf/authenticator.rb +56 -0
  12. data/lib/shaf/authenticator/base.rb +161 -0
  13. data/lib/shaf/authenticator/basic_auth.rb +25 -0
  14. data/lib/shaf/authenticator/challenge.rb +32 -0
  15. data/lib/shaf/authenticator/parameter.rb +31 -0
  16. data/lib/shaf/authenticator/request.rb +17 -0
  17. data/lib/shaf/command/console.rb +1 -1
  18. data/lib/shaf/command/generate.rb +5 -2
  19. data/lib/shaf/command/new.rb +20 -7
  20. data/lib/shaf/command/templates/Gemfile.erb +1 -0
  21. data/{templates/config/settings.yml → lib/shaf/command/templates/config/settings.yml.erb} +1 -5
  22. data/lib/shaf/errors.rb +11 -0
  23. data/lib/shaf/extensions.rb +3 -3
  24. data/lib/shaf/extensions/api_routes.rb +60 -0
  25. data/lib/shaf/extensions/authorize.rb +11 -9
  26. data/lib/shaf/extensions/log.rb +1 -1
  27. data/lib/shaf/extensions/resource_uris.rb +139 -63
  28. data/lib/shaf/extensions/symbolic_routes.rb +22 -19
  29. data/lib/shaf/formable.rb +1 -2
  30. data/lib/shaf/formable/form.rb +1 -1
  31. data/lib/shaf/generator.rb +2 -0
  32. data/lib/shaf/generator/base.rb +2 -3
  33. data/lib/shaf/generator/controller.rb +11 -7
  34. data/lib/shaf/generator/doc.rb +17 -0
  35. data/lib/shaf/generator/forms.rb +1 -0
  36. data/lib/shaf/generator/helper.rb +2 -1
  37. data/lib/shaf/generator/migration/base.rb +7 -3
  38. data/lib/shaf/generator/migration/type.rb +4 -26
  39. data/lib/shaf/generator/migration/types.rb +45 -16
  40. data/lib/shaf/generator/model.rb +1 -2
  41. data/lib/shaf/generator/profile.rb +52 -0
  42. data/lib/shaf/generator/serializer.rb +38 -73
  43. data/lib/shaf/generator/templates/api/policy.rb.erb +2 -2
  44. data/lib/shaf/generator/templates/api/profile.rb.erb +16 -0
  45. data/lib/shaf/generator/templates/api/serializer.rb.erb +2 -2
  46. data/lib/shaf/generator/templates/spec/integration_spec.rb.erb +1 -2
  47. data/lib/shaf/generator/templates/spec/serializer_spec.rb.erb +5 -5
  48. data/lib/shaf/helpers.rb +4 -0
  49. data/lib/shaf/helpers/authentication.rb +79 -0
  50. data/lib/shaf/helpers/cache_control.rb +1 -2
  51. data/lib/shaf/helpers/json_html.rb +58 -18
  52. data/lib/shaf/helpers/payload.rb +26 -41
  53. data/lib/shaf/helpers/vary.rb +8 -0
  54. data/lib/shaf/logger.rb +12 -0
  55. data/lib/shaf/parser.rb +65 -0
  56. data/lib/shaf/parser/base.rb +44 -0
  57. data/lib/shaf/parser/form_data.rb +15 -0
  58. data/lib/shaf/parser/json.rb +26 -0
  59. data/lib/shaf/profile.rb +115 -0
  60. data/lib/shaf/profile/attribute.rb +29 -0
  61. data/lib/shaf/profile/evaluator.rb +46 -0
  62. data/lib/shaf/profile/relation.rb +29 -0
  63. data/lib/shaf/profile/unique_id.rb +58 -0
  64. data/lib/shaf/profiles.rb +46 -0
  65. data/lib/shaf/profiles/shaf_basic.rb +20 -0
  66. data/lib/shaf/profiles/shaf_error.rb +49 -0
  67. data/lib/shaf/profiles/shaf_form.rb +110 -0
  68. data/lib/shaf/responder.rb +41 -2
  69. data/lib/shaf/responder/alps_json.rb +25 -0
  70. data/lib/shaf/responder/base.rb +20 -17
  71. data/lib/shaf/responder/hal.rb +63 -8
  72. data/lib/shaf/responder/html.rb +65 -9
  73. data/lib/shaf/responder/problem_json.rb +1 -1
  74. data/lib/shaf/serializer.rb +35 -0
  75. data/lib/shaf/settings.rb +25 -12
  76. data/lib/shaf/spec.rb +1 -0
  77. data/lib/shaf/spec/authenticator.rb +13 -0
  78. data/lib/shaf/spec/base.rb +1 -1
  79. data/lib/shaf/spec/http_method_utils.rb +1 -1
  80. data/lib/shaf/spec/integration_spec.rb +25 -13
  81. data/lib/shaf/spec/payload_utils.rb +2 -2
  82. data/lib/shaf/supported_http_methods.rb +15 -0
  83. data/lib/shaf/tasks/api_doc_task.rb +24 -3
  84. data/lib/shaf/tasks/routes_task.rb +14 -17
  85. data/lib/shaf/upgrade/manifest.rb +11 -2
  86. data/lib/shaf/upgrade/package.rb +78 -49
  87. data/lib/shaf/upgrade/version.rb +11 -10
  88. data/lib/shaf/utils.rb +19 -5
  89. data/lib/shaf/version.rb +3 -1
  90. data/lib/shaf/yard.rb +34 -0
  91. data/lib/shaf/yard/attribute_method_handler.rb +19 -0
  92. data/lib/shaf/yard/attribute_object.rb +30 -0
  93. data/lib/shaf/yard/base_method_handler.rb +30 -0
  94. data/lib/shaf/yard/link_method_handler.rb +39 -0
  95. data/lib/shaf/yard/link_object.rb +60 -0
  96. data/lib/shaf/yard/nested_attributes.rb +37 -0
  97. data/lib/shaf/yard/parser.rb +64 -0
  98. data/lib/shaf/yard/profile_method_handler.rb +51 -0
  99. data/lib/shaf/yard/profile_object.rb +21 -0
  100. data/lib/shaf/yard/resource_object.rb +55 -0
  101. data/lib/shaf/yard/serializer_handler.rb +27 -0
  102. data/templates/api/controllers/base_controller.rb +0 -10
  103. data/templates/api/controllers/docs_controller.rb +5 -3
  104. data/templates/api/controllers/root_controller.rb +7 -1
  105. data/templates/api/policies/base_policy.rb +2 -0
  106. data/templates/api/serializers/base_serializer.rb +1 -3
  107. data/templates/api/serializers/error_serializer.rb +1 -5
  108. data/templates/api/serializers/form_serializer.rb +1 -5
  109. data/templates/api/serializers/validation_error_serializer.rb +1 -5
  110. data/templates/config.ru +1 -1
  111. data/templates/config/bootstrap.rb +1 -2
  112. data/templates/config/directories.rb +52 -44
  113. data/templates/config/helpers.rb +1 -1
  114. data/templates/config/initializers.rb +52 -8
  115. data/templates/config/initializers/authentication.rb +18 -0
  116. data/templates/config/initializers/db_migrations.rb +2 -2
  117. data/templates/config/initializers/logging.rb +2 -2
  118. data/templates/frontend/assets/css/main.css +33 -1
  119. data/templates/frontend/views/headers.erb +20 -0
  120. data/templates/frontend/views/layout.erb +7 -1
  121. data/templates/frontend/views/payload.erb +1 -0
  122. data/templates/spec/spec_helper.rb +2 -0
  123. data/upgrades/0.5.0.tar.gz +0 -0
  124. data/upgrades/1.0.4.tar.gz +0 -0
  125. data/upgrades/1.1.0.tar.gz +0 -0
  126. data/upgrades/1.6.0.tar.gz +0 -0
  127. data/upgrades/1.6.1.tar.gz +0 -0
  128. data/upgrades/2.0.0.tar.gz +0 -0
  129. data/yard_templates/api_doc/doc_index/html/body.erb +3 -0
  130. data/yard_templates/api_doc/doc_index/setup.rb +8 -0
  131. data/yard_templates/api_doc/html/css/api-doc.css +222 -0
  132. data/yard_templates/api_doc/html/favicon.ico +0 -0
  133. data/yard_templates/api_doc/html/js/switch_tab.js +17 -0
  134. data/yard_templates/api_doc/html/setup.rb +59 -0
  135. data/yard_templates/api_doc/layout/html/footer.erb +3 -0
  136. data/yard_templates/api_doc/layout/html/header.erb +7 -0
  137. data/yard_templates/api_doc/layout/html/layout.erb +13 -0
  138. data/yard_templates/api_doc/layout/setup.rb +24 -0
  139. data/yard_templates/api_doc/profile/html/attributes.erb +10 -0
  140. data/yard_templates/api_doc/profile/html/profile.erb +6 -0
  141. data/yard_templates/api_doc/profile/html/relations.erb +10 -0
  142. data/yard_templates/api_doc/profile/setup.rb +38 -0
  143. data/yard_templates/api_doc/profile_attribute/html/attribute.erb +23 -0
  144. data/yard_templates/api_doc/profile_attribute/setup.rb +21 -0
  145. data/yard_templates/api_doc/profile_relation/html/relation.erb +37 -0
  146. data/yard_templates/api_doc/profile_relation/setup.rb +41 -0
  147. data/yard_templates/api_doc/resource/html/attributes.erb +10 -0
  148. data/yard_templates/api_doc/resource/html/profile.erb +14 -0
  149. data/yard_templates/api_doc/resource/html/relations.erb +10 -0
  150. data/yard_templates/api_doc/resource/html/resource.erb +5 -0
  151. data/yard_templates/api_doc/resource/setup.rb +56 -0
  152. data/yard_templates/api_doc/resource_attribute/html/attribute.erb +23 -0
  153. data/yard_templates/api_doc/resource_attribute/setup.rb +20 -0
  154. data/yard_templates/api_doc/resource_relation/html/relation.erb +47 -0
  155. data/yard_templates/api_doc/resource_relation/setup.rb +80 -0
  156. data/yard_templates/api_doc/setup.rb +31 -0
  157. data/yard_templates/api_doc/sidebar/html/profile_list.erb +8 -0
  158. data/yard_templates/api_doc/sidebar/html/search.erb +7 -0
  159. data/yard_templates/api_doc/sidebar/html/serializer_list.erb +8 -0
  160. data/yard_templates/api_doc/sidebar/html/sidebar.erb +13 -0
  161. data/yard_templates/api_doc/sidebar/setup.rb +56 -0
  162. metadata +140 -30
  163. metadata.gz.sig +0 -0
  164. data/lib/shaf/extensions/current_user.rb +0 -48
  165. data/lib/shaf/responder/hal_serializable.rb +0 -54
@@ -0,0 +1,222 @@
1
+ * {
2
+ box-sizing: border-box;
3
+ }
4
+
5
+ html {
6
+ margin: 0;
7
+ height: 100%;
8
+ }
9
+
10
+ body {
11
+ margin: 0;
12
+ height: 100%;
13
+ }
14
+
15
+ ul {
16
+ padding: 0;
17
+ list-style-type: none;
18
+ }
19
+
20
+ td {
21
+ min-width: 20em;
22
+ }
23
+
24
+ pre {
25
+ margin: 0;
26
+ }
27
+
28
+ .sidebar-content.list li {
29
+ margin-top: 0.4em;
30
+ }
31
+
32
+ a:link, a:visited {
33
+ color: black;
34
+ text-decoration: none;
35
+ font-weight: 500;
36
+ }
37
+
38
+ a:hover {
39
+ color: #008277;
40
+ }
41
+
42
+ .grid-container {
43
+ display: grid;
44
+ grid-template-columns: 320px auto 320px;
45
+ grid-template-rows: 4em auto 2em;
46
+ grid-template-areas:
47
+ "header-sidebar header-main header-none"
48
+ "sidebar resource none"
49
+ "footer footer footer";
50
+ height: 100%;
51
+ }
52
+
53
+ .header-sidebar {
54
+ grid-area: header-sidebar;
55
+ padding-left: 2em;
56
+ }
57
+
58
+ .header-sidebar h2 {
59
+ padding-top: 4px;
60
+ }
61
+
62
+ .header-main {
63
+ grid-area: header-main;
64
+ text-align: center;
65
+ width: 100%;
66
+ }
67
+
68
+ .header-none {
69
+ grid-area: header-none;
70
+ }
71
+
72
+ .header {
73
+ background-color: #bdc9d0;
74
+ font-size: 0.8em;
75
+ }
76
+
77
+ .sidebar {
78
+ grid-area: sidebar;
79
+ border-right: 1px solid;
80
+ border-color: #d2d2d2;
81
+ background-color: #e3e9ee;
82
+ height: 100%;
83
+ }
84
+
85
+ .sidebar-tabs {
86
+ overflow: hidden;
87
+ border-bottom: 1px solid;
88
+ padding-left: 1em;
89
+ border-color: #d2d2d2;
90
+ }
91
+
92
+ .sidebar-tabs button {
93
+ background-color: inherit;
94
+ border: none;
95
+ cursor: pointer;
96
+ padding: 1em;
97
+ font-weight: bold;
98
+ font-size: 1em;
99
+ transition: 0.5s;
100
+ }
101
+
102
+ .sidebar-tabs button:hover {
103
+ background-color: #b3d7d4;
104
+ }
105
+
106
+ .sidebar-tabs button.active {
107
+ text-decoration: underline;
108
+ text-decoration-color: #ff9e22;
109
+ }
110
+
111
+ /* .sidebar-search { */
112
+ /* padding: 1em 2em 0 2em; */
113
+ /* } */
114
+
115
+ .sidebar-content {
116
+ display: none;
117
+ padding: 1em 2em 0 2em;
118
+ }
119
+
120
+ .sidebar-content.active {
121
+ display: block;
122
+ }
123
+
124
+ li.sidebar-link.active a {
125
+ font-weight: bold;
126
+ text-decoration: underline;
127
+ text-decoration-color: #ff9e22;
128
+ text-decoration-style: solid;
129
+ }
130
+
131
+ .resource {
132
+ grid-area: resource;
133
+ padding: 2em;
134
+ /* background-color: #eeffee; */
135
+ background-color: #ffffff;
136
+ }
137
+
138
+ .footer {
139
+ grid-area: footer;
140
+ text-align: right;
141
+ width: 100%;
142
+ background-color: #ffffff;
143
+ font-size: 0.75em;
144
+ }
145
+
146
+ .resource-section {
147
+ margin-top: 4em;
148
+ }
149
+
150
+ span.resource-title {
151
+ font-style: italic;
152
+ }
153
+
154
+ .property-source {
155
+ padding: 4px;
156
+ border-radius: 4px;
157
+ margin-left: 0.5em;
158
+ }
159
+
160
+ .property-source.profile {
161
+ background-color: #a0ccf5;
162
+ }
163
+
164
+ .property-source.iana {
165
+ background-color: #c5e1a5;
166
+ }
167
+
168
+ .property-source.unknown {
169
+ background-color: #ef5350;
170
+ }
171
+
172
+ .nested-attributes {
173
+ padding-left: 2em;
174
+ }
175
+
176
+ .nested-attributes h5, h6 {
177
+ font-size: 1.0em;
178
+ }
179
+
180
+ h4.description-list {
181
+ margin-bottom: 8px;
182
+ }
183
+
184
+ li.description-item {
185
+ margin-top: 32px;
186
+ margin-bottom: 0;
187
+ }
188
+
189
+ .http-method {
190
+ margin-left: 0.5em;
191
+ border-radius: 4px;
192
+ padding: 4px;
193
+ background-color: #9e9e9e;
194
+ }
195
+
196
+ .http-method.head {
197
+ background-color: #8bc34a;
198
+ }
199
+
200
+ .http-method.options {
201
+ background-color: #90a4ae;
202
+ }
203
+
204
+ .http-method.get {
205
+ background-color: #42a5fa;
206
+ }
207
+
208
+ .http-method.put {
209
+ background-color: #ab47bc;
210
+ }
211
+
212
+ .http-method.patch {
213
+ background-color: #7e57c2;
214
+ }
215
+
216
+ .http-method.post {
217
+ background-color: #26c6da;
218
+ }
219
+
220
+ .http-method.delete {
221
+ background-color: #ff6d00;
222
+ }
@@ -0,0 +1,17 @@
1
+ function openTab(evt, tabName) {
2
+ // Declare all variables
3
+ var i, tabcontent, tablinks;
4
+
5
+ tabButtons = document.getElementsByClassName("sidebar-tab-btn");
6
+ for (i = 0; i < tabButtons.length; i++) {
7
+ tabButtons[i].className = tabButtons[i].className.replace(" active", "");
8
+ }
9
+
10
+ tabs = document.getElementsByClassName("sidebar-content");
11
+ for (i = 0; i < tabs.length; i++) {
12
+ tabs[i].className = tabs[i].className.replace(" active", "");
13
+ }
14
+
15
+ evt.currentTarget.className += " active";
16
+ document.getElementById(tabName).className += " active";
17
+ }
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ostruct'
4
+ require 'shaf/yard/profile_object'
5
+
6
+ def init
7
+ super
8
+
9
+ generate_index
10
+ generate_assets
11
+ generate_resources
12
+ generate_profiles
13
+ end
14
+
15
+ def generate_index
16
+ serialize(index_object)
17
+ end
18
+
19
+ def index_object
20
+ OpenStruct.new(
21
+ path: :index,
22
+ name: :index,
23
+ type: :doc_index
24
+ )
25
+ end
26
+
27
+ def generate_assets
28
+ Array(assets).each do |asset|
29
+ content = file(asset)
30
+ serializer(base_path: public_path).serialize(asset, content)
31
+ end
32
+ end
33
+
34
+ def generate_resources
35
+ options.resources.each do |resource|
36
+ serialize(resource)
37
+ end
38
+ end
39
+
40
+ def generate_profiles
41
+ options.profiles.each do |profile|
42
+ serialize(profile)
43
+ end
44
+ end
45
+
46
+ def serialize(object)
47
+ options.object = object
48
+ Templates::Engine.with_serializer(object, serializer) do
49
+ T('layout').run(options)
50
+ end
51
+ end
52
+
53
+ def assets
54
+ [
55
+ 'css/api-doc.css',
56
+ 'js/switch_tab.js',
57
+ 'favicon.ico',
58
+ ]
59
+ end
@@ -0,0 +1,3 @@
1
+ <div class="footer">
2
+ <p>Icon by <a href="https://freeicons.io/profile/3054">Nine One</a> on <a href="https://freeicons.io">freeicons.io</a></p>
3
+ </div>
@@ -0,0 +1,7 @@
1
+ <div class="header header-sidebar">
2
+ <h2><span><%= sub_title %></span></h2>
3
+ </div>
4
+ <div class="header header-main">
5
+ <h1><span><%= title %></span></h1>
6
+ </div>
7
+ <div class="header header-none"></div>
@@ -0,0 +1,13 @@
1
+ <html>
2
+ <head>
3
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
4
+ <title><%= title %></title>
5
+ <link rel="stylesheet" href="/css/api-doc.css" type="text/css" media="screen" charset="utf-8" />
6
+ <script type="text/javascript" charset="utf-8" src="/js/switch_tab.js"></script>
7
+ </head>
8
+ <body>
9
+ <div class="grid-container">
10
+ <%= yieldall %>
11
+ </div>
12
+ </body>
13
+ </html>
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ def init
4
+ super
5
+ return unless object
6
+
7
+ sections :layout, %i[header sidebar main footer]
8
+ end
9
+
10
+ def sidebar
11
+ Templates::Engine.render options.merge(type: :sidebar)
12
+ end
13
+
14
+ def main
15
+ Templates::Engine.render options
16
+ end
17
+
18
+ def sub_title
19
+ 'API documentation'
20
+ end
21
+
22
+ def title
23
+ Shaf::Settings.project_name
24
+ end
@@ -0,0 +1,10 @@
1
+ <div class="resource-section attributes">
2
+ <h3>Attributes</h3>
3
+ <ul>
4
+ <% @attributes.each do |attr| %>
5
+ <li class="description-item">
6
+ <%= serialize_attribute(attr) %>
7
+ </li>
8
+ <% end %>
9
+ </ul>
10
+ </div>
@@ -0,0 +1,6 @@
1
+ <%# FIXME: make classes more generic %>
2
+ <div class="resource">
3
+ <h2>The <span class="resource-title"><%= name %></span> profile</h2>
4
+ <p><%= description %>
5
+ <%= yieldall %>
6
+ </div>
@@ -0,0 +1,10 @@
1
+ <div class="resource-section relations">
2
+ <h3>Link relations</h3>
3
+ <ul>
4
+ <% @relations.each do |rel| %>
5
+ <li class="description-item">
6
+ <%= serialize_relation(rel) %>
7
+ </li>
8
+ <% end %>
9
+ </ul>
10
+ </div>
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ def init
4
+ super
5
+
6
+ return unless object.profile
7
+
8
+ @attributes = object.profile.attributes
9
+ @relations = object.profile.relations
10
+
11
+ sections :profile, [:attributes, :relations]
12
+ end
13
+
14
+ def serialize_attribute(attr)
15
+ Templates::Engine.render(
16
+ template: :api_doc,
17
+ type: :profile_attribute,
18
+ object: attr,
19
+ format: options.format
20
+ )
21
+ end
22
+
23
+ def serialize_relation(rel)
24
+ Templates::Engine.render(
25
+ template: :api_doc,
26
+ type: :profile_relation,
27
+ object: rel,
28
+ format: options.format
29
+ )
30
+ end
31
+
32
+ def name
33
+ object.profile_name
34
+ end
35
+
36
+ def description
37
+ object.description
38
+ end
@@ -0,0 +1,23 @@
1
+ <h4 class=description-list>
2
+ <strong> <%= object.name %></strong>
3
+ <% value_types.each do |type:, class_name:| %>
4
+ <span class="property-source <%= class_name %>"><%= type %></span>
5
+ <% end %>
6
+ </h4>
7
+ <p><%= object.doc %></p>
8
+ <% unless @nested_attributes.empty? %>
9
+ <div class="nested-attributes">
10
+ <h5>Nested attributes</h5>
11
+ <ul>
12
+ <% @nested_attributes.each do |key, attr| %>
13
+ <li>
14
+ <h6>
15
+ <strong> <%= key %></strong>
16
+ <span class="property-source profile"><%= attr.type %></span>
17
+ </h6>
18
+ <p><%= attr.doc %></p>
19
+ </li>
20
+ <% end %>
21
+ </ul>
22
+ </div>
23
+ <% end %>