shaf 2.1.0 → 3.0.0

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/shaf/app.rb +27 -9
  4. data/lib/shaf/command/base.rb +4 -0
  5. data/lib/shaf/command/new.rb +5 -1
  6. data/lib/shaf/command/server.rb +5 -1
  7. data/lib/shaf/command/templates/config/settings.yml.erb +9 -8
  8. data/lib/shaf/extensions/resource_uris.rb +37 -155
  9. data/lib/shaf/extensions/symbolic_routes.rb +5 -18
  10. data/lib/shaf/formable/builder.rb +58 -19
  11. data/lib/shaf/formable/form.rb +13 -10
  12. data/lib/shaf/formable.rb +10 -23
  13. data/lib/shaf/generator/base.rb +82 -0
  14. data/lib/shaf/generator/controller.rb +19 -35
  15. data/lib/shaf/generator/forms.rb +10 -14
  16. data/lib/shaf/generator/migration/add_column.rb +0 -4
  17. data/lib/shaf/generator/migration/add_index.rb +0 -4
  18. data/lib/shaf/generator/migration/base.rb +8 -0
  19. data/lib/shaf/generator/migration/create_table.rb +0 -4
  20. data/lib/shaf/generator/migration/drop_column.rb +0 -4
  21. data/lib/shaf/generator/migration/rename_column.rb +0 -4
  22. data/lib/shaf/generator/model.rb +29 -14
  23. data/lib/shaf/generator/policy.rb +8 -14
  24. data/lib/shaf/generator/profile.rb +9 -14
  25. data/lib/shaf/generator/scaffold.rb +6 -9
  26. data/lib/shaf/generator/serializer.rb +31 -30
  27. data/lib/shaf/generator/templates/api/controller.rb.erb +13 -13
  28. data/lib/shaf/generator/templates/api/forms.rb.erb +2 -2
  29. data/lib/shaf/generator/templates/api/model.rb.erb +1 -1
  30. data/lib/shaf/generator/templates/api/profile.rb.erb +1 -1
  31. data/lib/shaf/generator/templates/api/serializer.rb.erb +1 -1
  32. data/lib/shaf/generator/templates/spec/integration_spec.rb.erb +14 -14
  33. data/lib/shaf/helpers/paginate.rb +1 -1
  34. data/lib/shaf/profile.rb +8 -8
  35. data/lib/shaf/registrable_factory.rb +62 -32
  36. data/lib/shaf/responder/problem_json.rb +1 -1
  37. data/lib/shaf/router.rb +65 -12
  38. data/lib/shaf/spec/integration_spec.rb +1 -1
  39. data/lib/shaf/tasks.rb +0 -1
  40. data/lib/shaf/upgrade/package.rb +5 -7
  41. data/lib/shaf/version.rb +1 -1
  42. data/templates/Rakefile +0 -6
  43. data/templates/api/controllers/base_controller.rb +0 -2
  44. data/templates/api/serializers/root_serializer.rb +0 -11
  45. data/templates/config/initializers/middleware.rb +6 -0
  46. data/templates/spec/spec_helper.rb +4 -1
  47. data/upgrades/3.0.0.tar.gz +0 -0
  48. data.tar.gz.sig +0 -0
  49. metadata +19 -22
  50. metadata.gz.sig +0 -0
  51. data/lib/shaf/api_doc/comment.rb +0 -27
  52. data/lib/shaf/api_doc/document.rb +0 -137
  53. data/lib/shaf/api_doc/link_relations.rb +0 -77
  54. data/lib/shaf/middleware.rb +0 -1
  55. data/lib/shaf/tasks/api_doc_task.rb +0 -146
@@ -30,7 +30,7 @@ module Shaf
30
30
  end
31
31
 
32
32
  def app
33
- App.app
33
+ App.instance
34
34
  end
35
35
 
36
36
  def authenticate(user)
data/lib/shaf/tasks.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'shaf/tasks/test_task'
2
2
  require 'shaf/tasks/db_task'
3
- require 'shaf/tasks/api_doc_task'
4
3
  require 'shaf/tasks/routes_task'
5
4
 
6
5
  module Shaf
@@ -236,18 +236,16 @@ module Shaf
236
236
  replacement = params[:replace]
237
237
 
238
238
  changed = false
239
- tmp = Tempfile.open do |new_file|
239
+ new_content = ""
240
+ FT::ChangeFileCommand.execute(file) do
240
241
  File.readlines(file).each do |line|
241
242
  changed = line.gsub!(pattern, replacement) || changed
242
- new_file << line
243
+ new_content << line
243
244
  end
244
- new_file
245
+ new_content
245
246
  end
246
247
 
247
- return true unless changed
248
-
249
- puts "modifying file: #{file}"
250
- FT::MoveFileCommand.new(from: tmp.path, to: file).execute
248
+ puts "modifying file: #{file}" if changed
251
249
  true
252
250
  end
253
251
 
data/lib/shaf/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Shaf
4
- VERSION = '2.1.0'
4
+ VERSION = '3.0.0'
5
5
  end
data/templates/Rakefile CHANGED
@@ -5,12 +5,6 @@ $LOAD_PATH.unshift __dir__ unless $LOAD_PATH.include? __dir__
5
5
  require 'shaf/rake'
6
6
  require 'shaf/settings'
7
7
 
8
- Shaf::ApiDocTask.new do |api_doc|
9
- api_doc.source_dir = File.join(%w(api serializers))
10
- api_doc.html_output_dir = File.join(Shaf::Settings.public_folder, "doc")
11
- api_doc.yaml_output_dir = Shaf::Settings.documents_dir || "doc/api"
12
- end
13
-
14
8
  namespace :test do
15
9
  Shaf::TestTask.new(:integration) do |t|
16
10
  t.pattern = "spec/integration/**/*_spec.rb"
@@ -13,8 +13,6 @@ class BaseController < Sinatra::Base
13
13
  set :show_exceptions, :after_handler
14
14
  end
15
15
 
16
- use Rack::Deflater
17
-
18
16
  Shaf::Router.mount(self, default: true)
19
17
 
20
18
  register(*Shaf.extensions)
@@ -1,16 +1,5 @@
1
1
  require 'serializers/base_serializer'
2
2
 
3
3
  class RootSerializer < BaseSerializer
4
-
5
- # Auto generated doc:
6
- # Link to the root resource. All clients should fetch this resource
7
- # when starting to interact with this API.
8
- # Method: GET
9
- # Example:
10
- # ```
11
- # curl -H "Accept: application/json" \
12
- # -H "Authorization: abcdef" \
13
- # /
14
- #```
15
4
  link :self, root_uri
16
5
  end
@@ -0,0 +1,6 @@
1
+ require 'shaf/middleware/request_id'
2
+ require 'shaf/router'
3
+
4
+ Shaf::App.use Rack::Deflater
5
+ Shaf::App.use Shaf::Middleware::RequestId
6
+ Shaf::App.use Shaf::Router
@@ -4,4 +4,7 @@ require 'minitest/autorun'
4
4
  require 'minitest/hooks'
5
5
  require 'shaf/spec'
6
6
 
7
- Shaf::Spec::Authenticator.restricted { |id:| User[id] }
7
+ realm = Shaf::Settings.default_authentication_realm
8
+ Shaf::Spec::Authenticator.restricted realm: realm do |id:|
9
+ User[id]
10
+ end
Binary file
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shaf
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sammy Henningsson
@@ -29,7 +29,7 @@ cert_chain:
29
29
  5ZlcHq9h5CxVt380OKaU6wMg95RJBd/kUJqmPxxlxMH8QDQinTwZmmFA9wW7PJdy
30
30
  wAx8px9LkSjTs0GVLH7VtVRWAELllsswCJktz63Adelx9fmIMgrTYgZM
31
31
  -----END CERTIFICATE-----
32
- date: 2021-04-07 00:00:00.000000000 Z
32
+ date: 2021-10-03 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: file_transactions
@@ -149,20 +149,6 @@ dependencies:
149
149
  - - "~>"
150
150
  - !ruby/object:Gem::Version
151
151
  version: '0.9'
152
- - !ruby/object:Gem::Dependency
153
- name: redcarpet
154
- requirement: !ruby/object:Gem::Requirement
155
- requirements:
156
- - - "~>"
157
- - !ruby/object:Gem::Version
158
- version: '3.5'
159
- type: :development
160
- prerelease: false
161
- version_requirements: !ruby/object:Gem::Requirement
162
- requirements:
163
- - - "~>"
164
- - !ruby/object:Gem::Version
165
- version: '3.5'
166
152
  - !ruby/object:Gem::Dependency
167
153
  name: faraday
168
154
  requirement: !ruby/object:Gem::Requirement
@@ -219,6 +205,20 @@ dependencies:
219
205
  - - "~>"
220
206
  - !ruby/object:Gem::Version
221
207
  version: '1.6'
208
+ - !ruby/object:Gem::Dependency
209
+ name: byebug
210
+ requirement: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
215
+ type: :development
216
+ prerelease: false
217
+ version_requirements: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - ">="
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
222
222
  description: A framework for building hypermedia driven APIs with sinatra and sequel.
223
223
  email: sammy.henningsson@gmail.com
224
224
  executables:
@@ -232,9 +232,6 @@ files:
232
232
  - lib/shaf/alps/attribute_serializer.rb
233
233
  - lib/shaf/alps/json_serializer.rb
234
234
  - lib/shaf/alps/relation_serializer.rb
235
- - lib/shaf/api_doc/comment.rb
236
- - lib/shaf/api_doc/document.rb
237
- - lib/shaf/api_doc/link_relations.rb
238
235
  - lib/shaf/app.rb
239
236
  - lib/shaf/authenticator.rb
240
237
  - lib/shaf/authenticator/base.rb
@@ -308,7 +305,6 @@ files:
308
305
  - lib/shaf/helpers/vary.rb
309
306
  - lib/shaf/immutable_attr.rb
310
307
  - lib/shaf/logger.rb
311
- - lib/shaf/middleware.rb
312
308
  - lib/shaf/middleware/request_id.rb
313
309
  - lib/shaf/parser.rb
314
310
  - lib/shaf/parser/base.rb
@@ -352,7 +348,6 @@ files:
352
348
  - lib/shaf/spec/system_spec.rb
353
349
  - lib/shaf/supported_http_methods.rb
354
350
  - lib/shaf/tasks.rb
355
- - lib/shaf/tasks/api_doc_task.rb
356
351
  - lib/shaf/tasks/db_task.rb
357
352
  - lib/shaf/tasks/routes_task.rb
358
353
  - lib/shaf/tasks/test_task.rb
@@ -397,6 +392,7 @@ files:
397
392
  - templates/config/initializers/db_migrations.rb
398
393
  - templates/config/initializers/hal_presenter.rb
399
394
  - templates/config/initializers/logging.rb
395
+ - templates/config/initializers/middleware.rb
400
396
  - templates/config/initializers/sequel.rb
401
397
  - templates/config/paths.rb
402
398
  - templates/frontend/assets/css/main.css
@@ -422,6 +418,7 @@ files:
422
418
  - upgrades/1.6.0.tar.gz
423
419
  - upgrades/1.6.1.tar.gz
424
420
  - upgrades/2.0.0.tar.gz
421
+ - upgrades/3.0.0.tar.gz
425
422
  - yard_templates/api_doc/doc_index/html/body.erb
426
423
  - yard_templates/api_doc/doc_index/setup.rb
427
424
  - yard_templates/api_doc/html/css/api-doc.css
@@ -476,7 +473,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
476
473
  - !ruby/object:Gem::Version
477
474
  version: '0'
478
475
  requirements: []
479
- rubygems_version: 3.0.3
476
+ rubygems_version: 3.1.4
480
477
  signing_key:
481
478
  specification_version: 4
482
479
  summary: Sinatra Hypermedia Api Framework
metadata.gz.sig CHANGED
Binary file
@@ -1,27 +0,0 @@
1
- module Shaf
2
- module ApiDoc
3
- class Comment
4
- def initialize
5
- @indent = 0
6
- @comment = ""
7
- end
8
-
9
- def to_s
10
- @comment
11
- end
12
-
13
- def empty?
14
- @comment.empty?
15
- end
16
-
17
- def <<(line)
18
- @indent = line[/\A\s*/].size if empty?
19
- @comment << "\n#{extract(line)}"
20
- end
21
-
22
- def extract(line)
23
- line.sub(%r(\A\s{#{@indent}}), "")
24
- end
25
- end
26
- end
27
- end
@@ -1,137 +0,0 @@
1
- require 'fileutils'
2
- require 'yaml'
3
- require 'redcarpet'
4
- require 'redcarpet/render_strip'
5
-
6
- module Shaf
7
- module ApiDoc
8
- class Document
9
- attr_writer :model
10
- attr_accessor :serializer_class, :policy, :attributes, :links, :curies, :embeds
11
-
12
- def initialize
13
- @model = nil
14
- @serializer_class = nil
15
- @policy = nil
16
- @attributes = {}
17
- @links = {}
18
- @curies = {}
19
- @embeds = {}
20
- @md = {}
21
- end
22
-
23
- def model
24
- @model || @serializer_class && @serializer_class.sub("Serializer", "")
25
- end
26
-
27
- def attribute(attr, comment)
28
- @attributes[attr] = comment unless comment.empty?
29
- end
30
-
31
- def link(rel, comment)
32
- @links[strip_curie(rel)] = comment unless comment.empty?
33
- end
34
-
35
- def curie(rel, comment)
36
- @curies[rel] = comment unless comment.empty?
37
- end
38
-
39
- def embedded(name, comment)
40
- @embeds[strip_curie(name)] = comment unless comment.empty?
41
- end
42
-
43
- def valid?
44
- return false unless model
45
- attributes.merge(links).merge(curies).any?
46
- end
47
-
48
- def generate_markdown!
49
- return @md unless @md.empty?
50
-
51
- generate_title!
52
- generate_policy!
53
- generate_section!(key: :attributes, heading: "Attributes")
54
- generate_section!(key: :curies, heading: "Curies", sub_title: "rel")
55
- generate_section!(key: :links, heading: "Links", sub_title: "rel")
56
- generate_section!(key: :embeds, heading: "Embedded resources", sub_title: "rel")
57
- @md[:doc]
58
- end
59
-
60
- def generate_yaml!
61
- generate_markdown!
62
- renderer = Redcarpet::Markdown.new(Redcarpet::Render::StripDown)
63
-
64
- hash = {}
65
- hash['policy'] = renderer.render(@md[:policy]).chomp if @md[:policy]
66
-
67
- [:attributes, :curies, :links, :embeds].each do |key|
68
- hash[key.to_s] = @md[key].map { |k, v| [k.to_s, renderer.render(v).chomp] }.to_h
69
- end
70
- hash.to_yaml
71
- end
72
-
73
- def markdown
74
- generate_markdown!
75
- @md[:doc]
76
- end
77
-
78
- def to_html
79
- options = {autolink: true, fenced_code_blocks: true}
80
- markdown_renderer = Redcarpet::Markdown.new(Redcarpet::Render::HTML, options)
81
- html = markdown_renderer.render markdown
82
- # For some reason redcarpet don't like to surround my markdown code blocks
83
- # with <pre> tags, so let's fix that here.
84
- html.gsub!("<code>", "<pre><code>")
85
- html.gsub!("</code>", "</code></pre>")
86
- html
87
- end
88
-
89
- def write_html(output)
90
- FileUtils.mkdir_p(output) unless Dir.exist? output
91
- File.open(File.join(output, "#{model.downcase}.html"), "w") do |file|
92
- file.write(to_html)
93
- end
94
- end
95
-
96
- def write_yaml(output)
97
- FileUtils.mkdir_p(output) unless Dir.exist? output
98
- File.open(File.join(output, "#{model.downcase}.yml"), "w") do |file|
99
- file.write(generate_yaml!)
100
- end
101
- end
102
-
103
-
104
- private
105
-
106
- def strip_curie(rel)
107
- rel.split(':', 2)[1] || rel
108
- end
109
-
110
- def generate_title!
111
- @md[:doc] = "# #{model.capitalize}\n"
112
- @md[:title] = model.capitalize
113
- end
114
-
115
- def generate_policy!
116
- return if policy.nil?
117
- @md[:doc] << "## Policy\n#{policy}\n"
118
- @md[:policy] = policy
119
- end
120
-
121
- def generate_section!(key:, heading:, sub_title: "")
122
- list = send(key)
123
- @md[:doc] << "## #{heading}\n"
124
- @md[key] = {}
125
- if list.empty?
126
- @md[:doc] << "This resource does not have any documented #{heading.downcase}\n"
127
- else
128
- sub_title += ": " unless sub_title.empty?
129
- list.each do |name, comment|
130
- @md[:doc] << "- *#{sub_title}#{name.tr('_', '-')}*\n #{comment.to_s.gsub("\n", "\n ")}\n\n"
131
- @md[key][name] = comment.to_s.chomp
132
- end
133
- end
134
- end
135
- end
136
- end
137
- end
@@ -1,77 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'net/http'
4
- require 'tempfile'
5
- require 'uri'
6
- require 'csv'
7
-
8
- module Shaf
9
- module ApiDoc
10
- class LinkRelations
11
- class LinkRelation
12
- attr_reader :name, :description, :reference, :notes
13
-
14
- def initialize(name, description, reference, notes)
15
- @name = name.to_sym
16
- @description = description.freeze
17
- @reference = reference.freeze
18
- @notes = notes.freeze
19
- end
20
- end
21
-
22
- class << self
23
- IANA_URL = URI('https://www.iana.org/assignments/link-relations/link-relations-1.csv')
24
-
25
- def all
26
- relations.values
27
- end
28
-
29
- def [](key)
30
- relations[key]
31
- end
32
-
33
- def []=(key, value)
34
- relations[key] = value
35
- end
36
-
37
- def add(link_relation)
38
- relations[link_relation.name] = link_relation
39
- end
40
-
41
- def load_iana
42
- csv.each do |name, desc, ref, notes|
43
- next if name == 'Relation Name'
44
- add LinkRelation.new(name, desc, ref, notes)
45
- end
46
- end
47
-
48
- private
49
-
50
- def relations
51
- @relations ||= {}
52
- end
53
-
54
- def tmp_file_name
55
- File.join(Dir.tmpdir, 'shaf_iana_link_relations')
56
- end
57
-
58
- def csv
59
- if File.readable? tmp_file_name
60
- content = File.read(tmp_file_name)
61
- return CSV.new(content)
62
- end
63
-
64
- response = Net::HTTP.get_response(IANA_URL)
65
-
66
- if response.code.to_i == 200
67
- content = response.body
68
- File.open(tmp_file_name, 'w') { |file| file.write(content) }
69
- CSV.new(content)
70
- else
71
- Utils.iana_link_relations_csv
72
- end
73
- end
74
- end
75
- end
76
- end
77
- end
@@ -1 +0,0 @@
1
- require 'shaf/middleware/request_id'
@@ -1,146 +0,0 @@
1
- module Shaf
2
- module Tasks
3
- class ApiDocTask
4
- include Rake::DSL
5
-
6
- attr_accessor :document_class, :source_dir, :html_output_dir, :yaml_output_dir
7
-
8
- def initialize
9
- return show_deprecation_message if RUBY_VERSION >= '3.0.0'
10
-
11
- require 'shaf/api_doc/document'
12
- require 'shaf/api_doc/comment'
13
-
14
- yield self if block_given?
15
- validate_attributes!
16
- @document_class ||= ApiDoc::Document
17
- define_tasks
18
- end
19
-
20
- def validate_attributes!
21
- raise "source_dir must be set!" unless source_dir
22
- raise "html_output_dir must be configured in ApiDocTask" unless html_output_dir
23
- raise "yaml_output_dir must be configured in ApiDocTask" unless yaml_output_dir
24
- end
25
-
26
- def define_tasks
27
- namespace :doc do
28
- desc "Generate API documentation"
29
- task :generate do
30
- show_deprecation_message
31
-
32
- files = Dir.glob(File.join(source_dir, "*.rb"))
33
- files.each do |file|
34
- read_file file do |doc|
35
- next unless doc.valid?
36
- doc.write_html @html_output_dir
37
- doc.write_yaml @yaml_output_dir
38
- end
39
- end
40
- end
41
-
42
- desc "Remove generated documentation"
43
- task :clean do
44
- [
45
- Dir.glob(File.join(@yaml_output_dir, "*.yml")),
46
- Dir.glob(File.join(@html_output_dir, "*.html"))
47
- ].flatten.each do |file|
48
- File.unlink file
49
- end
50
- end
51
- end
52
- end
53
-
54
- def show_deprecation_message
55
- ruby3_msg = <<~RUBY3 if RUBY_VERSION >= '3.0.0'
56
-
57
- Due to errors with the Redcarpet gem it's not possible to use this deprecated rake task with Ruby >= 3.0.0
58
- If you need to continue with this task please use an older version of Ruby.
59
- RUBY3
60
-
61
- puts <<~MSG
62
- This way of generating documentation is DEPRECATED.#{ruby3_msg}
63
-
64
- Please move the documentation comments into profiles instead and run:
65
- shaf generate doc
66
- See https://github.com/sammyhenningsson/shaf/blob/main/doc/DOCUMENTATION.md for more info
67
-
68
- MSG
69
- end
70
-
71
- def read_file(file)
72
- doc = document_class.new
73
- comment = ApiDoc::Comment.new
74
-
75
- File.readlines(file).each do |line|
76
- next if empty_line?(line)
77
-
78
- if c = comment(line)
79
- comment << c
80
- next
81
- end
82
-
83
- parse_line(line, doc, comment)
84
- comment = ApiDoc::Comment.new
85
- end
86
-
87
- return doc unless block_given?
88
- yield doc
89
- end
90
-
91
- def parse_line(line, doc, comment)
92
- if model = model(line)
93
- doc.model = model
94
- elsif serializer_class = serializer_class(line)
95
- doc.serializer_class = serializer_class
96
- elsif policy = policy(line)
97
- doc.policy = policy
98
- elsif attr = attribute(line)
99
- doc.attribute(attr, comment)
100
- elsif rel = link(line)
101
- doc.link(rel, comment)
102
- elsif rel = curie(line)
103
- doc.curie(rel, comment)
104
- elsif name = embed(line)
105
- doc.embedded(name, comment)
106
- end
107
- end
108
-
109
- def empty_line?(line)
110
- true if line[/\A[#\s*]*\Z/]
111
- end
112
-
113
- def serializer_class(line)
114
- line[/\A\s*class\s*(\w+)\Z/, 1]
115
- end
116
-
117
- def model(line)
118
- line[/\A\s*model\s*(?:::)?(\w+)/, 1]
119
- end
120
-
121
- def policy(line)
122
- line[/\A\s*policy\s*(?:::)?(\w+)/, 1]
123
- end
124
-
125
- def comment(line)
126
- line[/\A\s*#(.*)/, 1]
127
- end
128
-
129
- def attribute(line)
130
- line[/\A\s*attribute\s+\(?:(\w+)/, 1]
131
- end
132
-
133
- def link(line)
134
- line[/\A\s*link\s+\(?:?['"]?([-:\w]+)['"]?/, 1]
135
- end
136
-
137
- def curie(line)
138
- line[/\A\s*curie\s+\(?:'?([-\w]+)'?/, 1]
139
- end
140
-
141
- def embed(line)
142
- line[/\A\s*embed\s+\(?:'?([-:\w]+)'?/, 1]
143
- end
144
- end
145
- end
146
- end