shaf 0.1.0.beta
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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -0
- data/bin/shaf +57 -0
- data/lib/shaf.rb +9 -0
- data/lib/shaf/api_doc.rb +124 -0
- data/lib/shaf/api_doc/comment.rb +27 -0
- data/lib/shaf/api_doc/document.rb +133 -0
- data/lib/shaf/app.rb +22 -0
- data/lib/shaf/command.rb +42 -0
- data/lib/shaf/command/console.rb +17 -0
- data/lib/shaf/command/generate.rb +19 -0
- data/lib/shaf/command/new.rb +79 -0
- data/lib/shaf/command/server.rb +15 -0
- data/lib/shaf/command/templates/Gemfile.erb +30 -0
- data/lib/shaf/doc_model.rb +54 -0
- data/lib/shaf/errors.rb +77 -0
- data/lib/shaf/extensions.rb +11 -0
- data/lib/shaf/extensions/authorize.rb +42 -0
- data/lib/shaf/extensions/resource_uris.rb +153 -0
- data/lib/shaf/formable.rb +188 -0
- data/lib/shaf/generator.rb +69 -0
- data/lib/shaf/generator/controller.rb +106 -0
- data/lib/shaf/generator/migration.rb +122 -0
- data/lib/shaf/generator/migration/add_column.rb +49 -0
- data/lib/shaf/generator/migration/create_table.rb +40 -0
- data/lib/shaf/generator/migration/drop_column.rb +45 -0
- data/lib/shaf/generator/migration/empty.rb +21 -0
- data/lib/shaf/generator/migration/rename_column.rb +48 -0
- data/lib/shaf/generator/model.rb +68 -0
- data/lib/shaf/generator/policy.rb +43 -0
- data/lib/shaf/generator/scaffold.rb +26 -0
- data/lib/shaf/generator/serializer.rb +258 -0
- data/lib/shaf/generator/templates/api/controller.rb.erb +62 -0
- data/lib/shaf/generator/templates/api/model.rb.erb +20 -0
- data/lib/shaf/generator/templates/api/policy.rb.erb +26 -0
- data/lib/shaf/generator/templates/api/serializer.rb.erb +24 -0
- data/lib/shaf/generator/templates/spec/integration_spec.rb.erb +98 -0
- data/lib/shaf/generator/templates/spec/model.rb.erb +40 -0
- data/lib/shaf/generator/templates/spec/serializer_spec.rb.erb +46 -0
- data/lib/shaf/helpers.rb +15 -0
- data/lib/shaf/helpers/json_html.rb +65 -0
- data/lib/shaf/helpers/paginate.rb +24 -0
- data/lib/shaf/helpers/payload.rb +115 -0
- data/lib/shaf/helpers/session.rb +53 -0
- data/lib/shaf/middleware.rb +1 -0
- data/lib/shaf/middleware/request_id.rb +16 -0
- data/lib/shaf/registrable_factory.rb +71 -0
- data/lib/shaf/settings.rb +33 -0
- data/lib/shaf/spec.rb +6 -0
- data/lib/shaf/spec/http_method_utils.rb +24 -0
- data/lib/shaf/spec/integration_spec.rb +53 -0
- data/lib/shaf/spec/model.rb +17 -0
- data/lib/shaf/spec/payload_test.rb +78 -0
- data/lib/shaf/spec/payload_utils.rb +176 -0
- data/lib/shaf/spec/serializer_spec.rb +24 -0
- data/lib/shaf/tasks.rb +4 -0
- data/lib/shaf/tasks/db.rb +61 -0
- data/lib/shaf/tasks/test.rb +43 -0
- data/lib/shaf/utils.rb +53 -0
- data/lib/shaf/version.rb +3 -0
- data/templates/Rakefile +13 -0
- data/templates/api/controllers/base_controller.rb +57 -0
- data/templates/api/controllers/docs_controller.rb +16 -0
- data/templates/api/controllers/root_controller.rb +8 -0
- data/templates/api/serializers/error_serializer.rb +10 -0
- data/templates/api/serializers/form_serializer.rb +42 -0
- data/templates/api/serializers/root_serializer.rb +16 -0
- data/templates/config.ru +4 -0
- data/templates/config/bootstrap.rb +12 -0
- data/templates/config/constants.rb +5 -0
- data/templates/config/customize.rb +3 -0
- data/templates/config/database.rb +40 -0
- data/templates/config/directories.rb +32 -0
- data/templates/config/helpers.rb +18 -0
- data/templates/config/initializers.rb +12 -0
- data/templates/config/initializers/db_migrations.rb +18 -0
- data/templates/config/initializers/hal_presenter.rb +6 -0
- data/templates/config/initializers/logging.rb +7 -0
- data/templates/config/initializers/sequel.rb +4 -0
- data/templates/config/settings.yml +19 -0
- data/templates/frontend/assets/css/main.css +70 -0
- data/templates/frontend/views/form.erb +16 -0
- data/templates/frontend/views/layout.erb +11 -0
- data/templates/frontend/views/payload.erb +8 -0
- data/templates/spec/integration/root_spec.rb +14 -0
- data/templates/spec/serializers/root_serializer_spec.rb +12 -0
- data/templates/spec/spec_helper.rb +4 -0
- metadata +348 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f841c557430b49c07e938734ae86d33572a7d6fa2b7ca5a65ae3c85d0a88cd65
|
4
|
+
data.tar.gz: b01be584adcba338f10942a79b80a2f55625383e880b119de5c5f9a53212e196
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4e9006af2484b780d9d41781d8060c58658c6c398152353e475d8f4c8832fc8397589d1798d9e805faa71bf8de537c63453493c8c67cae74190261b1a0236294
|
7
|
+
data.tar.gz: 2f62a554a41c79cd42a2669e6c844ece355db39a829754abe5dec7d81055949d88be6954ee4874b261181060374a06310b63790e7ed944edd521f8def10af942
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
�q''�@e-<���Í�[%݁�cHݖ��p�[ pj�u��[^����M@K7�!���v������V-u�J��ה}/��I8�:�Ti���g����ӥ��]R�6*��5"�机�-����3�Ex=�.mhHc�iF��]��7=�T��0},�$4Ϙ�O՝���*@X�s�/�es�f�����G7��;��"�}��4,Qso^�"#@]��Ч6��D��C��T�!��x������
|
data/bin/shaf
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'shaf/utils'
|
4
|
+
require 'shaf/command'
|
5
|
+
require 'shaf/settings'
|
6
|
+
|
7
|
+
module Shaf
|
8
|
+
class Script
|
9
|
+
include Utils
|
10
|
+
|
11
|
+
def self.run
|
12
|
+
new.run
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
check_customizations
|
17
|
+
return show_help if show_help?
|
18
|
+
Command::Factory.create(*ARGV).call
|
19
|
+
rescue RegistrableFactory::NotFoundError, Command::ArgumentError => e
|
20
|
+
puts e.message, "\n"
|
21
|
+
show_help
|
22
|
+
exit 1
|
23
|
+
rescue Utils::ProjectRootNotFound
|
24
|
+
puts "This command can only be executed inside a Shaf project directory. " \
|
25
|
+
"Please change directory and try again!"
|
26
|
+
exit 2
|
27
|
+
end
|
28
|
+
|
29
|
+
def show_help
|
30
|
+
puts "Usage: #{script_name} #{usage}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def script_name
|
34
|
+
File.basename $0
|
35
|
+
end
|
36
|
+
|
37
|
+
def usage
|
38
|
+
Command::Factory.usage.join("\n ")
|
39
|
+
end
|
40
|
+
|
41
|
+
def show_help?
|
42
|
+
ARGV.first =~ /-h/
|
43
|
+
end
|
44
|
+
|
45
|
+
def check_customizations
|
46
|
+
return unless project_root
|
47
|
+
|
48
|
+
in_project_root do
|
49
|
+
ENV['RACK_ENV'] ||= 'development'
|
50
|
+
next unless File.exist? 'config/customize.rb'
|
51
|
+
require 'config/customize'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Shaf::Script.run
|
data/lib/shaf.rb
ADDED
data/lib/shaf/api_doc.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'shaf/api_doc/document'
|
2
|
+
|
3
|
+
module Shaf
|
4
|
+
module ApiDoc
|
5
|
+
class Task
|
6
|
+
include Rake::DSL
|
7
|
+
|
8
|
+
attr_accessor :document_class, :source_dir, :html_output_dir, :yaml_output_dir
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
yield self if block_given?
|
12
|
+
validate_attributes!
|
13
|
+
@document_class ||= Document
|
14
|
+
define_tasks
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate_attributes!
|
18
|
+
raise "source_dir must be set!" unless source_dir
|
19
|
+
raise "html_output_dir must be configured in ApiDocTask" unless html_output_dir
|
20
|
+
raise "yaml_output_dir must be configured in ApiDocTask" unless yaml_output_dir
|
21
|
+
end
|
22
|
+
|
23
|
+
def define_tasks
|
24
|
+
namespace :doc do
|
25
|
+
desc "Generate API documentation"
|
26
|
+
task :generate do
|
27
|
+
files = Dir.glob(File.join(source_dir, "*.rb"))
|
28
|
+
files.each do |file|
|
29
|
+
read_file file do |doc|
|
30
|
+
next unless doc.has_enough_info?
|
31
|
+
doc.write_html @html_output_dir
|
32
|
+
doc.write_yaml @yaml_output_dir
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "Remove generated documentation"
|
38
|
+
task :clean do
|
39
|
+
[
|
40
|
+
Dir.glob(File.join(@yaml_output_dir, "*.yml")),
|
41
|
+
Dir.glob(File.join(@html_output_dir, "*.html"))
|
42
|
+
].flatten.each do |file|
|
43
|
+
File.unlink file
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def read_file(file)
|
50
|
+
doc = document_class.new
|
51
|
+
comment = Comment.new
|
52
|
+
|
53
|
+
File.readlines(file).each do |line|
|
54
|
+
next if empty_line?(line)
|
55
|
+
|
56
|
+
if c = comment(line)
|
57
|
+
comment << c
|
58
|
+
next
|
59
|
+
end
|
60
|
+
|
61
|
+
parse_line(line, doc, comment)
|
62
|
+
comment = Comment.new
|
63
|
+
end
|
64
|
+
|
65
|
+
return doc unless block_given?
|
66
|
+
yield doc
|
67
|
+
end
|
68
|
+
|
69
|
+
def parse_line(line, doc, comment)
|
70
|
+
if model = model(line)
|
71
|
+
doc.model = model
|
72
|
+
elsif serializer_class = serializer_class(line)
|
73
|
+
doc.serializer_class = serializer_class
|
74
|
+
elsif policy = policy(line)
|
75
|
+
doc.policy = policy
|
76
|
+
elsif attr = attribute(line)
|
77
|
+
doc.attribute(attr, comment)
|
78
|
+
elsif rel = link(line)
|
79
|
+
doc.link(rel, comment)
|
80
|
+
elsif rel = curie(line)
|
81
|
+
doc.curie(rel, comment)
|
82
|
+
elsif name = embed(line)
|
83
|
+
doc.embedded(name, comment)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def empty_line?(line)
|
88
|
+
true if line[/\A[#\s*]*\Z/]
|
89
|
+
end
|
90
|
+
|
91
|
+
def serializer_class(line)
|
92
|
+
line[/\A\s*class\s*(\w+)\Z/, 1]
|
93
|
+
end
|
94
|
+
|
95
|
+
def model(line)
|
96
|
+
line[/\A\s*model\s*(?:::)?(\w+)/, 1]
|
97
|
+
end
|
98
|
+
|
99
|
+
def policy(line)
|
100
|
+
line[/\A\s*policy\s*(?:::)?(\w+)/, 1]
|
101
|
+
end
|
102
|
+
|
103
|
+
def comment(line)
|
104
|
+
line[/\A\s*#(.*)/, 1]
|
105
|
+
end
|
106
|
+
|
107
|
+
def attribute(line)
|
108
|
+
line[/\A\s*attribute[^s]\s*\(?\s*:(\w+)/, 1]
|
109
|
+
end
|
110
|
+
|
111
|
+
def link(line)
|
112
|
+
line[/\A\s*link\s*\(?\s*:'?([-:\w]+)'?/, 1]
|
113
|
+
end
|
114
|
+
|
115
|
+
def curie(line)
|
116
|
+
line[/\A\s*curie\s*\(?\s*:'?([-\w]+)'?/, 1]
|
117
|
+
end
|
118
|
+
|
119
|
+
def embed(line)
|
120
|
+
line[/\A\s*embed\s*\(?\s*:'?([-:\w]+)'?/, 1]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,27 @@
|
|
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
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'yaml'
|
3
|
+
require 'redcarpet'
|
4
|
+
require 'redcarpet/render_strip'
|
5
|
+
require 'shaf/api_doc/comment'
|
6
|
+
|
7
|
+
module Shaf
|
8
|
+
module ApiDoc
|
9
|
+
class Document
|
10
|
+
attr_writer :model
|
11
|
+
attr_accessor :serializer_class, :policy, :attributes, :links, :curies, :embeds
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@model = nil
|
15
|
+
@serializer_class = nil
|
16
|
+
@policy = nil
|
17
|
+
@attributes = {}
|
18
|
+
@links = {}
|
19
|
+
@curies = {}
|
20
|
+
@embeds = {}
|
21
|
+
@md = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def model
|
25
|
+
@model || @serializer_class && @serializer_class.sub("Serializer", "")
|
26
|
+
end
|
27
|
+
|
28
|
+
def attribute(attr, comment)
|
29
|
+
@attributes[attr] = comment unless comment.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
def link(rel, comment)
|
33
|
+
@links[strip_curie(rel)] = comment unless comment.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
def curie(rel, comment)
|
37
|
+
@curies[rel] = comment unless comment.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
def embedded(name, comment)
|
41
|
+
@embeds[strip_curie(name)] = comment unless comment.empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
def has_enough_info?
|
45
|
+
return false unless model
|
46
|
+
attributes.merge(links).merge(curies).any?
|
47
|
+
end
|
48
|
+
|
49
|
+
def generate_markdown!
|
50
|
+
return @md unless @md.empty?
|
51
|
+
|
52
|
+
generate_title!
|
53
|
+
generate_policy!
|
54
|
+
generate_section!(key: :attributes, heading: "Attributes")
|
55
|
+
generate_section!(key: :curies, heading: "Curies", sub_title: "rel")
|
56
|
+
generate_section!(key: :links, heading: "Links", sub_title: "rel")
|
57
|
+
generate_section!(key: :embeds, heading: "Embedded resources", sub_title: "rel")
|
58
|
+
@md[:doc]
|
59
|
+
end
|
60
|
+
|
61
|
+
def generate_yaml!
|
62
|
+
generate_markdown!
|
63
|
+
renderer = Redcarpet::Markdown.new(Redcarpet::Render::StripDown)
|
64
|
+
|
65
|
+
hash = {}
|
66
|
+
hash['policy'] = renderer.render(@md[:policy]).chomp if @md[:policy]
|
67
|
+
|
68
|
+
[:attributes, :curies, :links, :embeds].each do |key|
|
69
|
+
hash[key.to_s] = @md[key].map { |k, v| [k.to_s, renderer.render(v).chomp] }.to_h
|
70
|
+
end
|
71
|
+
hash.to_yaml
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_markdown
|
75
|
+
# For some reason redcarpet don't like to surround my markdown code blocks
|
76
|
+
# with <pre> tags, so let's fix that here.
|
77
|
+
options = {autolink: true, fenced_code_blocks: true}
|
78
|
+
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, options)
|
79
|
+
html = markdown.render(generate_markdown!)
|
80
|
+
html.gsub!("<code>", "<pre><code>")
|
81
|
+
html.gsub!("</code>", "</code></pre>")
|
82
|
+
html
|
83
|
+
end
|
84
|
+
|
85
|
+
def write_html(output)
|
86
|
+
FileUtils.mkdir_p(output) unless Dir.exist? output
|
87
|
+
File.open(File.join(output, "#{model.downcase}.html"), "w") do |file|
|
88
|
+
file.write(to_markdown)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def write_yaml(output)
|
93
|
+
FileUtils.mkdir_p(output) unless Dir.exist? output
|
94
|
+
File.open(File.join(output, "#{model.downcase}.yml"), "w") do |file|
|
95
|
+
file.write(generate_yaml!)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def strip_curie(rel)
|
103
|
+
rel.split(':', 2)[1] || rel
|
104
|
+
end
|
105
|
+
|
106
|
+
def generate_title!
|
107
|
+
@md[:doc] = "##%s\n" % model.capitalize
|
108
|
+
@md[:title] = model.capitalize
|
109
|
+
end
|
110
|
+
|
111
|
+
def generate_policy!
|
112
|
+
return if policy.nil?
|
113
|
+
@md[:doc] << "###Policy\n#{policy}\n"
|
114
|
+
@md[:policy] = policy
|
115
|
+
end
|
116
|
+
|
117
|
+
def generate_section!(key:, heading:, sub_title: "")
|
118
|
+
list = send(key)
|
119
|
+
@md[:doc] << "####{heading}\n"
|
120
|
+
@md[key] = {}
|
121
|
+
if list.empty?
|
122
|
+
@md[:doc] << "This resource does not have any documented #{heading.downcase}\n"
|
123
|
+
else
|
124
|
+
sub_title << ": " unless sub_title.empty?
|
125
|
+
list.each do |name, comment|
|
126
|
+
@md[:doc] << "#######{sub_title}#{name.gsub('_', '-')}\n#{comment.to_s}\n"
|
127
|
+
@md[key][name] = comment.to_s.chomp
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
data/lib/shaf/app.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'shaf/middleware'
|
2
|
+
|
3
|
+
module Shaf
|
4
|
+
class App
|
5
|
+
class << self
|
6
|
+
def instance
|
7
|
+
create_instance unless defined?(@instance)
|
8
|
+
@instance
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_instance
|
12
|
+
@instance = Sinatra.new
|
13
|
+
@instance.set :port, Shaf::Settings.port || 3000
|
14
|
+
@instance.use Shaf::Middleware::RequestId
|
15
|
+
end
|
16
|
+
|
17
|
+
def use(middleware)
|
18
|
+
instance.use middleware
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/shaf/command.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'shaf/utils'
|
2
|
+
require 'shaf/registrable_factory'
|
3
|
+
|
4
|
+
module Shaf
|
5
|
+
module Command
|
6
|
+
|
7
|
+
class ArgumentError < StandardError; end
|
8
|
+
|
9
|
+
class Factory
|
10
|
+
extend RegistrableFactory
|
11
|
+
end
|
12
|
+
|
13
|
+
class Base
|
14
|
+
include Utils
|
15
|
+
|
16
|
+
attr_reader :args
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def inherited(child)
|
20
|
+
Factory.register(child)
|
21
|
+
end
|
22
|
+
|
23
|
+
def identifier(*ids)
|
24
|
+
@identifiers = ids.flatten
|
25
|
+
end
|
26
|
+
|
27
|
+
def usage(str = nil, &block)
|
28
|
+
@usage = str || block
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(*args)
|
33
|
+
@args = args.dup
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
require 'shaf/command/new'
|
40
|
+
require 'shaf/command/server'
|
41
|
+
require 'shaf/command/console'
|
42
|
+
require 'shaf/command/generate'
|