pliny 0.2.1 → 0.3.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.
- checksums.yaml +14 -6
- data/README.md +59 -11
- data/bin/pliny-generate +2 -14
- data/bin/pliny-new +1 -1
- data/lib/pliny.rb +1 -2
- data/lib/pliny/commands/creator.rb +10 -11
- data/lib/pliny/commands/generator.rb +50 -199
- data/lib/pliny/commands/generator/base.rb +59 -0
- data/lib/pliny/commands/generator/endpoint.rb +44 -0
- data/lib/pliny/commands/generator/mediator.rb +21 -0
- data/lib/pliny/commands/generator/migration.rb +13 -0
- data/lib/pliny/commands/generator/model.rb +30 -0
- data/lib/pliny/commands/generator/schema.rb +24 -0
- data/lib/pliny/commands/generator/serializer.rb +21 -0
- data/lib/pliny/config_helpers.rb +52 -0
- data/lib/pliny/helpers/encode.rb +7 -0
- data/lib/pliny/log.rb +18 -1
- data/lib/pliny/middleware/versioning.rb +3 -3
- data/lib/pliny/tasks/db.rake +21 -7
- data/lib/pliny/tasks/schema.rake +2 -2
- data/lib/pliny/templates/endpoint.erb +5 -5
- data/lib/pliny/templates/endpoint_acceptance_test.erb +1 -1
- data/lib/pliny/templates/endpoint_scaffold.erb +5 -5
- data/lib/pliny/templates/endpoint_scaffold_acceptance_test.erb +1 -1
- data/lib/pliny/templates/endpoint_test.erb +1 -0
- data/lib/pliny/templates/migration.erb +0 -2
- data/lib/pliny/templates/model.erb +0 -2
- data/lib/pliny/templates/model_test.erb +0 -1
- data/lib/pliny/templates/serializer_test.erb +0 -1
- data/lib/pliny/version.rb +1 -1
- data/template/.env.sample +2 -1
- data/template/README.md +1 -1
- data/template/bin/console +1 -3
- data/template/bin/run +1 -3
- data/template/config.ru +1 -4
- data/template/config/config.rb +19 -25
- data/template/config/initializers/rollbar.rb +1 -0
- data/template/config/puma.rb +2 -2
- data/template/db/schema.sql +1 -2
- data/template/lib/application.rb +4 -0
- data/template/lib/endpoints/base.rb +1 -0
- data/template/lib/routes.rb +1 -1
- data/template/lib/serializers/base.rb +8 -1
- data/test/commands/creator_test.rb +1 -0
- data/test/commands/generator/base_test.rb +103 -0
- data/test/commands/generator/endpoint_test.rb +15 -0
- data/test/commands/generator_test.rb +95 -134
- data/test/log_test.rb +16 -0
- metadata +100 -69
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'erb'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'pliny'
|
6
|
+
|
7
|
+
module Pliny::Commands
|
8
|
+
class Generator
|
9
|
+
class Base
|
10
|
+
attr_reader :name, :stream, :options
|
11
|
+
|
12
|
+
def initialize(name, options = {}, stream = $stdout)
|
13
|
+
@name = name
|
14
|
+
@options = options
|
15
|
+
@stream = stream
|
16
|
+
end
|
17
|
+
|
18
|
+
def singular_class_name
|
19
|
+
name.gsub(/-/, '_').singularize.camelize
|
20
|
+
end
|
21
|
+
|
22
|
+
def plural_class_name
|
23
|
+
name.gsub(/-/, '_').pluralize.camelize
|
24
|
+
end
|
25
|
+
|
26
|
+
def field_name
|
27
|
+
name.tableize.singularize
|
28
|
+
end
|
29
|
+
|
30
|
+
def pluralized_file_name
|
31
|
+
name.tableize
|
32
|
+
end
|
33
|
+
|
34
|
+
def table_name
|
35
|
+
name.tableize.gsub('/', '_')
|
36
|
+
end
|
37
|
+
|
38
|
+
def display(msg)
|
39
|
+
stream.puts msg
|
40
|
+
end
|
41
|
+
|
42
|
+
def render_template(template_file, destination_path, vars = {})
|
43
|
+
template_path = File.dirname(__FILE__) + "/../../templates/#{template_file}"
|
44
|
+
template = ERB.new(File.read(template_path), 0, '>')
|
45
|
+
context = OpenStruct.new(vars)
|
46
|
+
write_file(destination_path) do
|
47
|
+
template.result(context.instance_eval { binding })
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def write_file(destination_path)
|
52
|
+
FileUtils.mkdir_p(File.dirname(destination_path))
|
53
|
+
File.open(destination_path, 'w') do |f|
|
54
|
+
f.puts yield
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Pliny::Commands
|
4
|
+
class Generator
|
5
|
+
class Endpoint < Base
|
6
|
+
def create
|
7
|
+
endpoint = "./lib/endpoints/#{pluralized_file_name}.rb"
|
8
|
+
template = options[:scaffold] ? 'endpoint_scaffold.erb' : 'endpoint.erb'
|
9
|
+
render_template(template, endpoint,
|
10
|
+
plural_class_name: plural_class_name,
|
11
|
+
singular_class_name: singular_class_name,
|
12
|
+
field_name: field_name,
|
13
|
+
url_path: url_path)
|
14
|
+
display "created endpoint file #{endpoint}"
|
15
|
+
display 'add the following to lib/routes.rb:'
|
16
|
+
display " mount Endpoints::#{plural_class_name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_test
|
20
|
+
test = "./spec/endpoints/#{pluralized_file_name}_spec.rb"
|
21
|
+
render_template('endpoint_test.erb', test,
|
22
|
+
plural_class_name: plural_class_name,
|
23
|
+
singular_class_name: singular_class_name,
|
24
|
+
url_path: url_path)
|
25
|
+
display "created test #{test}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_acceptance_test
|
29
|
+
test = "./spec/acceptance/#{pluralized_file_name}_spec.rb"
|
30
|
+
template = options[:scaffold] ? 'endpoint_scaffold_acceptance_test.erb' : 'endpoint_acceptance_test.erb'
|
31
|
+
render_template(template, test,
|
32
|
+
plural_class_name: plural_class_name,
|
33
|
+
field_name: field_name,
|
34
|
+
singular_class_name: singular_class_name,
|
35
|
+
url_path: url_path)
|
36
|
+
display "created test #{test}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def url_path
|
40
|
+
'/' + name.pluralize.gsub(/_/, '-')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Pliny::Commands
|
4
|
+
class Generator
|
5
|
+
class Mediator < Base
|
6
|
+
def create
|
7
|
+
mediator = "./lib/mediators/#{field_name}.rb"
|
8
|
+
render_template('mediator.erb', mediator,
|
9
|
+
singular_class_name: singular_class_name)
|
10
|
+
display "created mediator file #{mediator}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_test
|
14
|
+
test = "./spec/mediators/#{field_name}_spec.rb"
|
15
|
+
render_template('mediator_test.erb', test,
|
16
|
+
singular_class_name: singular_class_name)
|
17
|
+
display "created test #{test}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Pliny::Commands
|
4
|
+
class Generator
|
5
|
+
class Migration < Base
|
6
|
+
def create
|
7
|
+
migration = "./db/migrate/#{Time.now.to_i}_#{name}.rb"
|
8
|
+
render_template('migration.erb', migration)
|
9
|
+
display "created migration #{migration}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Pliny::Commands
|
4
|
+
class Generator
|
5
|
+
class Model < Base
|
6
|
+
def create
|
7
|
+
model = "./lib/models/#{field_name}.rb"
|
8
|
+
render_template('model.erb', model,
|
9
|
+
singular_class_name: singular_class_name,
|
10
|
+
paranoid: options[:paranoid])
|
11
|
+
display "created model file #{model}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_migration
|
15
|
+
migration = "./db/migrate/#{Time.now.to_i}_create_#{table_name}.rb"
|
16
|
+
render_template('model_migration.erb', migration,
|
17
|
+
table_name: table_name,
|
18
|
+
paranoid: options[:paranoid])
|
19
|
+
display "created migration #{migration}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_test
|
23
|
+
test = "./spec/models/#{field_name}_spec.rb"
|
24
|
+
render_template('model_test.erb', test,
|
25
|
+
singular_class_name: singular_class_name)
|
26
|
+
display "created test #{test}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
require 'prmd'
|
3
|
+
|
4
|
+
module Pliny::Commands
|
5
|
+
class Generator
|
6
|
+
class Schema < Base
|
7
|
+
def create
|
8
|
+
schema = "./docs/schema/schemata/#{field_name}.yaml"
|
9
|
+
write_file(schema) do
|
10
|
+
Prmd.init(name.singularize, yaml: true)
|
11
|
+
end
|
12
|
+
display "created schema file #{schema}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def rebuild
|
16
|
+
schemata = './docs/schema.json'
|
17
|
+
write_file(schemata) do
|
18
|
+
Prmd.combine('./docs/schema/schemata', meta: './docs/schema/meta.json')
|
19
|
+
end
|
20
|
+
display "rebuilt #{schemata}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Pliny::Commands
|
4
|
+
class Generator
|
5
|
+
class Serializer < Base
|
6
|
+
def create
|
7
|
+
serializer = "./lib/serializers/#{name}.rb"
|
8
|
+
render_template('serializer.erb', serializer,
|
9
|
+
singular_class_name: singular_class_name)
|
10
|
+
display "created serializer file #{serializer}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_test
|
14
|
+
test = "./spec/serializers/#{name}_spec.rb"
|
15
|
+
render_template('serializer_test.erb', test,
|
16
|
+
singular_class_name: singular_class_name)
|
17
|
+
display "created test #{test}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/pliny/config_helpers.rb
CHANGED
@@ -1,4 +1,55 @@
|
|
1
1
|
module Pliny
|
2
|
+
module CastingConfigHelpers
|
3
|
+
def mandatory(name, method=nil)
|
4
|
+
value = cast(ENV.fetch(name.to_s.upcase), method)
|
5
|
+
create(name, value)
|
6
|
+
end
|
7
|
+
|
8
|
+
def optional(name, method=nil)
|
9
|
+
value = cast(ENV[name.to_s.upcase], method)
|
10
|
+
create(name, value)
|
11
|
+
end
|
12
|
+
|
13
|
+
def override(name, default, method=nil)
|
14
|
+
value = cast(ENV.fetch(name.to_s.upcase, default), method)
|
15
|
+
create(name, value)
|
16
|
+
end
|
17
|
+
|
18
|
+
def int
|
19
|
+
->(v) { v.to_i }
|
20
|
+
end
|
21
|
+
|
22
|
+
def float
|
23
|
+
->(v) { v.to_f }
|
24
|
+
end
|
25
|
+
|
26
|
+
def bool
|
27
|
+
->(v) { v.to_s=='true'}
|
28
|
+
end
|
29
|
+
|
30
|
+
def string
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def symbol
|
35
|
+
->(v) { v.to_sym }
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def cast(value, method)
|
41
|
+
method ? method.call(value) : value
|
42
|
+
end
|
43
|
+
|
44
|
+
def create(name, value)
|
45
|
+
instance_variable_set(:"@#{name}", value)
|
46
|
+
instance_eval "def #{name}; @#{name} end", __FILE__, __LINE__
|
47
|
+
if value.kind_of?(TrueClass) || value.kind_of?(FalseClass) || value.kind_of?(NilClass)
|
48
|
+
instance_eval "def #{name}?; !!@#{name} end", __FILE__, __LINE__
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
2
53
|
module ConfigHelpers
|
3
54
|
def optional(*attrs)
|
4
55
|
attrs.each do |attr|
|
@@ -28,6 +79,7 @@ module Pliny
|
|
28
79
|
end
|
29
80
|
end
|
30
81
|
end
|
82
|
+
|
31
83
|
end
|
32
84
|
|
33
85
|
# Supress the "use RbConfig instead" warning.
|
data/lib/pliny/log.rb
CHANGED
@@ -1,10 +1,19 @@
|
|
1
1
|
module Pliny
|
2
2
|
module Log
|
3
3
|
def log(data, &block)
|
4
|
-
data = log_context.merge(data)
|
4
|
+
data = log_context.merge(local_context.merge(data))
|
5
5
|
log_to_stream(stdout || $stdout, data, &block)
|
6
6
|
end
|
7
7
|
|
8
|
+
def context(data, &block)
|
9
|
+
old = local_context
|
10
|
+
self.local_context = old.merge(data)
|
11
|
+
res = block.call
|
12
|
+
ensure
|
13
|
+
local_context = old
|
14
|
+
res
|
15
|
+
end
|
16
|
+
|
8
17
|
def stdout=(stream)
|
9
18
|
@stdout = stream
|
10
19
|
end
|
@@ -15,6 +24,14 @@ module Pliny
|
|
15
24
|
|
16
25
|
private
|
17
26
|
|
27
|
+
def local_context
|
28
|
+
RequestStore.store[:local_context] ||= {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def local_context=(h)
|
32
|
+
RequestStore.store[:local_context] = h
|
33
|
+
end
|
34
|
+
|
18
35
|
def log_context
|
19
36
|
RequestStore.store[:log_context] || {}
|
20
37
|
end
|
@@ -22,7 +22,7 @@ module Pliny::Middleware
|
|
22
22
|
version = nil
|
23
23
|
media_types.map! do |media_type|
|
24
24
|
if accept_headers.include?(media_type.format)
|
25
|
-
|
25
|
+
unless media_type.params['version']
|
26
26
|
error = { id: :bad_version, message: <<-eos }
|
27
27
|
Please specify a version along with the MIME type. For example, `Accept: application/vnd.#{@app_name}+json; version=1`.
|
28
28
|
eos
|
@@ -30,7 +30,7 @@ Please specify a version along with the MIME type. For example, `Accept: applica
|
|
30
30
|
[MultiJson.encode(error)]]
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
unless version
|
34
34
|
version = media_type.params["version"]
|
35
35
|
end
|
36
36
|
|
@@ -41,7 +41,7 @@ Please specify a version along with the MIME type. For example, `Accept: applica
|
|
41
41
|
end
|
42
42
|
media_type.to_s
|
43
43
|
end
|
44
|
-
env[
|
44
|
+
env['HTTP_ACCEPT'] = media_types.join(', ')
|
45
45
|
|
46
46
|
version ||= @default
|
47
47
|
set_api_version(env, version)
|
data/lib/pliny/tasks/db.rake
CHANGED
@@ -78,19 +78,33 @@ namespace :db do
|
|
78
78
|
namespace :schema do
|
79
79
|
desc "Load the database schema"
|
80
80
|
task :load do
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
81
|
+
if File.exists?("./db/schema.sql")
|
82
|
+
schema = File.read("./db/schema.sql")
|
83
|
+
database_urls.each do |database_url|
|
84
|
+
db = Sequel.connect(database_url)
|
85
|
+
db.run(schema)
|
86
|
+
puts "Loaded `#{name_from_uri(database_url)}`"
|
87
|
+
end
|
88
|
+
else
|
89
|
+
puts "Skipped schema load, schema.sql not present"
|
86
90
|
end
|
87
91
|
end
|
88
92
|
|
89
93
|
desc "Dump the database schema"
|
90
94
|
task :dump do
|
95
|
+
file = File.join("db", "schema.sql")
|
91
96
|
database_url = database_urls.first
|
92
|
-
`pg_dump -i -s -x -O -f
|
93
|
-
|
97
|
+
`pg_dump -i -s -x -O -f #{file} #{database_url}`
|
98
|
+
|
99
|
+
schema = File.read(file)
|
100
|
+
# filter all COMMENT ON EXTENSION, only owners and the db
|
101
|
+
# superuser can execute these, making it impossible to just
|
102
|
+
# replay such statements in certain production databases
|
103
|
+
schema.gsub!(/^COMMENT ON EXTENSION.*\n/, "")
|
104
|
+
|
105
|
+
File.open(file, "w") { |f| f.puts schema }
|
106
|
+
|
107
|
+
puts "Dumped `#{name_from_uri(database_url)}` to #{file}"
|
94
108
|
end
|
95
109
|
|
96
110
|
desc "Merges migrations into schema and removes them"
|
data/lib/pliny/tasks/schema.rake
CHANGED
@@ -6,24 +6,24 @@ module Endpoints
|
|
6
6
|
end
|
7
7
|
|
8
8
|
get do
|
9
|
-
|
9
|
+
encode []
|
10
10
|
end
|
11
11
|
|
12
12
|
post do
|
13
13
|
status 201
|
14
|
-
|
14
|
+
encode {}
|
15
15
|
end
|
16
16
|
|
17
17
|
get "/:id" do
|
18
|
-
|
18
|
+
encode {}
|
19
19
|
end
|
20
20
|
|
21
21
|
patch "/:id" do |id|
|
22
|
-
|
22
|
+
encode {}
|
23
23
|
end
|
24
24
|
|
25
25
|
delete "/:id" do |id|
|
26
|
-
|
26
|
+
encode {}
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -20,7 +20,7 @@ describe Endpoints::<%= plural_class_name %> do
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
describe 'POST <%= url_path
|
23
|
+
describe 'POST <%= url_path %>' do
|
24
24
|
it 'returns correct status code and conforms to schema' do
|
25
25
|
header "Content-Type", "application/json"
|
26
26
|
post '<%= url_path %>', MultiJson.encode({})
|