shaf 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/bin/shaf +3 -0
  5. data/lib/shaf.rb +1 -0
  6. data/lib/shaf/api_doc/document.rb +0 -1
  7. data/lib/shaf/app.rb +1 -1
  8. data/lib/shaf/command.rb +19 -2
  9. data/lib/shaf/command/generate.rb +11 -1
  10. data/lib/shaf/command/new.rb +1 -6
  11. data/lib/shaf/command/server.rb +7 -0
  12. data/lib/shaf/command/upgrade.rb +38 -0
  13. data/lib/shaf/extensions/authorize.rb +8 -6
  14. data/lib/shaf/extensions/resource_uris.rb +129 -71
  15. data/lib/shaf/generator.rb +4 -0
  16. data/lib/shaf/generator/controller.rb +2 -2
  17. data/lib/shaf/generator/migration.rb +33 -14
  18. data/lib/shaf/generator/migration/add_column.rb +1 -3
  19. data/lib/shaf/generator/migration/add_index.rb +42 -0
  20. data/lib/shaf/generator/model.rb +4 -4
  21. data/lib/shaf/generator/policy.rb +1 -1
  22. data/lib/shaf/generator/scaffold.rb +3 -3
  23. data/lib/shaf/generator/serializer.rb +5 -5
  24. data/lib/shaf/rake.rb +5 -0
  25. data/lib/shaf/rake/db.rb +79 -0
  26. data/lib/shaf/rake/test.rb +32 -0
  27. data/lib/shaf/registrable_factory.rb +8 -3
  28. data/lib/shaf/settings.rb +20 -4
  29. data/lib/shaf/tasks.rb +6 -3
  30. data/lib/shaf/{api_doc/task.rb → tasks/api_doc_task.rb} +6 -5
  31. data/lib/shaf/tasks/db_task.rb +42 -0
  32. data/lib/shaf/tasks/test_task.rb +16 -0
  33. data/lib/shaf/upgrade.rb +3 -0
  34. data/lib/shaf/upgrade/manifest.rb +31 -0
  35. data/lib/shaf/upgrade/package.rb +158 -0
  36. data/lib/shaf/upgrade/version.rb +52 -0
  37. data/lib/shaf/utils.rb +30 -0
  38. data/lib/shaf/version.rb +1 -1
  39. data/templates/Rakefile +2 -3
  40. data/templates/config/database.rb +3 -3
  41. metadata +33 -202
  42. metadata.gz.sig +0 -0
  43. data/lib/shaf/api_doc.rb +0 -3
  44. data/lib/shaf/tasks/db.rb +0 -81
  45. data/lib/shaf/tasks/test.rb +0 -48
@@ -24,12 +24,16 @@ module Shaf
24
24
  def usage(str = nil, &block)
25
25
  @usage = str || block
26
26
  end
27
+
28
+ def options(option_parser, options); end
27
29
  end
28
30
 
29
31
  def initialize(*args)
30
32
  @args = args.dup
31
33
  end
32
34
 
35
+ def call(options = {}); end
36
+
33
37
  def template_dir
34
38
  File.expand_path('../generator/templates', __FILE__)
35
39
  end
@@ -5,9 +5,9 @@ module Shaf
5
5
  identifier :controller
6
6
  usage 'generate controller RESOURCE_NAME [attribute:type] [..]'
7
7
 
8
- def call
8
+ def call(options = {})
9
9
  create_controller
10
- create_integration_spec
10
+ create_integration_spec if options[:specs]
11
11
  add_link_to_root
12
12
  end
13
13
 
@@ -23,19 +23,24 @@ module Shaf
23
23
 
24
24
  class Base
25
25
  DB_COL_TYPES = {
26
- integer: ['Integer :%s', ':%s, Integer'],
27
- varchar: ['String %s', ':%s, String'],
28
- string: ['String :%s', ':%s, String'],
29
- text: ['String :%s, text: true', ':%s, String, text: true'],
30
- blob: ['File :%s', ':%s, File'],
31
- bigint: ['Bignum :%s', ':%s, Bignum'],
32
- double: ['Float :%s', ':%s, Float'],
33
- numeric: ['BigDecimal :%s', ':%s, BigDecimal'],
34
- date: ['Date :%s', ':%s, Date'],
35
- timestamp: ['DateTime :%s', ':%s, DateTime'],
36
- time: ['Time :%s', ':%s, Time'],
37
- bool: ['TrueClass :%s', ':%s, TrueClass'],
38
- boolean: ['TrueClass :%s', ':%s, TrueClass'],
26
+ integer: ['Integer :%s', 'add_column :%s, Integer'],
27
+ varchar: ['String %s', 'add_column :%s, String'],
28
+ string: ['String :%s', 'add_column :%s, String'],
29
+ text: ['String :%s, text: true', 'add_column :%s, String, text: true'],
30
+ blob: ['File :%s', 'add_column :%s, File'],
31
+ bigint: ['Bignum :%s', 'add_column :%s, Bignum'],
32
+ double: ['Float :%s', 'add_column :%s, Float'],
33
+ numeric: ['BigDecimal :%s', 'add_column :%s, BigDecimal'],
34
+ date: ['Date :%s', 'add_column :%s, Date'],
35
+ timestamp: ['DateTime :%s', 'add_column :%s, DateTime'],
36
+ time: ['Time :%s', 'add_column :%s, Time'],
37
+ bool: ['TrueClass :%s', 'add_column :%s, TrueClass'],
38
+ boolean: ['TrueClass :%s', 'add_column :%s, TrueClass'],
39
+ index: ['index :%s, unique: true', 'add_index :%s'],
40
+ }
41
+
42
+ REGEXP_DB_TYPES = {
43
+ /\Aforeign_key\((\w+)\)/ => ['foreign_key :%s, :\1', 'add_foreign_key :%s, :\1'],
39
44
  }
40
45
 
41
46
  attr_reader :args
@@ -74,7 +79,13 @@ module Shaf
74
79
 
75
80
  def db_type(type)
76
81
  type ||= :string
77
- DB_COL_TYPES[type.to_sym] or raise "Column type '#{type}' not supported"
82
+ result = DB_COL_TYPES[type.to_sym]
83
+ result ||= REGEXP_DB_TYPES.each do |pattern, strings|
84
+ m = pattern.match(type) or next
85
+ break strings.map { |a| replace_backreferences(m, a) }
86
+ end
87
+ raise "Column type '#{type}' not supported" unless result
88
+ result
78
89
  end
79
90
 
80
91
  def column_def(str, create: true)
@@ -93,6 +104,13 @@ module Shaf
93
104
  DateTime.now.strftime("%Y%m%d%H%M%S")
94
105
  end
95
106
 
107
+ def replace_backreferences(match, str)
108
+ groups = match.size
109
+ (1...groups).inject(str) do |s, i|
110
+ s.gsub("\\#{i}", match[i])
111
+ end
112
+ end
113
+
96
114
  def add_timestamp_columns?
97
115
  if File.exist? 'config/initializers/sequel.rb'
98
116
  require 'config/initializers/sequel'
@@ -116,6 +134,7 @@ module Shaf
116
134
  end
117
135
 
118
136
  require 'shaf/generator/migration/add_column'
137
+ require 'shaf/generator/migration/add_index'
119
138
  require 'shaf/generator/migration/create_table'
120
139
  require 'shaf/generator/migration/drop_column'
121
140
  require 'shaf/generator/migration/empty'
@@ -34,9 +34,7 @@ module Shaf
34
34
  end
35
35
 
36
36
  def add_columns_change
37
- cols = columns.map do |s|
38
- "add_column #{column_def(s, create: false)}"
39
- end
37
+ cols = columns.map { |s| column_def(s, create: false) }
40
38
  [
41
39
  "alter_table(:#{table_name}) do",
42
40
  *cols.map { |col| col.prepend(" ") }, # indent body with 2 spaces
@@ -0,0 +1,42 @@
1
+ module Shaf
2
+ module Generator
3
+ module Migration
4
+ class AddIndex < Base
5
+
6
+ identifier %w(add index)
7
+ usage 'generate migration add index TABLE_NAME COLUMN_NAME'
8
+
9
+ def validate_args
10
+ if (table_name || "").empty? || (column || "").empty?
11
+ raise "Please provide a table and the column to create index on"
12
+ end
13
+ end
14
+
15
+ def compile_migration_name
16
+ "add_#{column}_index_to_#{table_name}"
17
+ end
18
+
19
+ def table_name
20
+ args.first
21
+ end
22
+
23
+ def compile_changes
24
+ add_change add_index_change
25
+ end
26
+
27
+ def column
28
+ args[1]
29
+ end
30
+
31
+ def add_index_change
32
+ col_def = column_def("#{column}:index", create: false)
33
+ [
34
+ "alter_table(:#{table_name}) do",
35
+ col_def.prepend(" "), # indent body with 2 spaces
36
+ "end\n"
37
+ ]
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -5,10 +5,10 @@ module Shaf
5
5
  identifier :model
6
6
  usage 'generate model MODEL_NAME [attribute:type] [..]'
7
7
 
8
- def call
8
+ def call(options = {})
9
9
  create_model
10
10
  create_migration
11
- create_serializer
11
+ create_serializer(options)
12
12
  end
13
13
 
14
14
  def model_name
@@ -61,10 +61,10 @@ module Shaf
61
61
  Migration::Generator.new(*migration_args).call
62
62
  end
63
63
 
64
- def create_serializer
64
+ def create_serializer(options)
65
65
  serializer_args = %W(serializer #{model_name})
66
66
  serializer_args += args[1..-1].map { |arg| arg.split(':').first }
67
- Generator::Factory.create(*serializer_args).call
67
+ Generator::Factory.create(*serializer_args).call(options)
68
68
  end
69
69
  end
70
70
  end
@@ -4,7 +4,7 @@ module Shaf
4
4
  identifier :policy
5
5
  usage 'generate policy MODEL_NAME [attribute] [..]'
6
6
 
7
- def call
7
+ def call(options = {})
8
8
  create_policy
9
9
  end
10
10
 
@@ -5,13 +5,13 @@ module Shaf
5
5
  identifier :scaffold
6
6
  usage 'generate scaffold RESOURCE_NAME [attribute:type] [..]'
7
7
 
8
- def call
8
+ def call(options = {})
9
9
  if name.empty?
10
10
  raise "Please provide a resource name when using the scaffold generator!"
11
11
  end
12
12
 
13
- Generator::Factory.create('model', *args).call
14
- Generator::Factory.create('controller', *controller_args).call
13
+ Generator::Factory.create('model', *args).call(options)
14
+ Generator::Factory.create('controller', *controller_args).call(options)
15
15
  end
16
16
 
17
17
  def name
@@ -4,10 +4,10 @@ module Shaf
4
4
  identifier :serializer
5
5
  usage 'generate serializer MODEL_NAME [attribute] [..]'
6
6
 
7
- def call
7
+ def call(options = {})
8
8
  create_serializer
9
- create_serializer_spec
10
- create_policy
9
+ create_serializer_spec if options[:specs]
10
+ create_policy(options)
11
11
  end
12
12
 
13
13
  def name
@@ -248,9 +248,9 @@ module Shaf
248
248
  }
249
249
  end
250
250
 
251
- def create_policy
251
+ def create_policy(options)
252
252
  policy_args = ["policy", name, *args[1..-1]]
253
- Generator::Factory.create(*policy_args).call
253
+ Generator::Factory.create(*policy_args).call(options)
254
254
  end
255
255
  end
256
256
  end
data/lib/shaf/rake.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'shaf/settings'
2
+ require 'shaf/tasks'
3
+ require 'shaf/rake/db'
4
+ require 'shaf/rake/test'
5
+
@@ -0,0 +1,79 @@
1
+ Shaf::DbTask.new(:version, description: "Prints current schema version") do
2
+ if migrations.any?
3
+ version, filename = extract_version_and_filename(last_migration)
4
+ puts "Schema version: #{version} (#{filename})"
5
+ else
6
+ puts "No migrations found"
7
+ end
8
+ end
9
+
10
+ Shaf::DbTask.new(:versions, description: "Prints all schema versions") do
11
+ if migrations.any?
12
+ migrations.each do |migration|
13
+ version, filename = extract_version_and_filename(migration)
14
+ next unless version && filename
15
+ puts "#{version}: #{filename}"
16
+ end
17
+ else
18
+ puts "No migrations found"
19
+ end
20
+ end
21
+
22
+ Shaf::DbTask.new(:migrate, description: "Run migrations", args: [:version]) do |t, args|
23
+ if args[:version]
24
+ puts "Migrating to version #{args[:version]}"
25
+ Sequel::Migrator.run(DB, MIGRATIONS_DIR, target: args[:version].to_i)
26
+ else
27
+ puts "Migrating to latest"
28
+ Sequel::Migrator.run(DB, MIGRATIONS_DIR)
29
+ end
30
+ end
31
+
32
+ Shaf::DbTask.new(
33
+ :rollback,
34
+ description: "Perform rollback to specified number of steps back or to the previous version",
35
+ args: [:target]
36
+ ) do |t, args|
37
+
38
+ args.with_defaults(target: 1)
39
+ target = -(args[:target].to_i + 1)
40
+ target = 0 if -target > migrations.size
41
+ migration = migrations.dig(target, :filename)
42
+ version, _ = extract_version_and_filename(migration)
43
+
44
+ warn_if_rolling_back_more_than = 5
45
+ if target == 0 || -target > warn_if_rolling_back_more_than
46
+ puts "This would migrate the Database to version: #{version}. Continue [N/y]?"
47
+ next unless /\Ay/i =~ STDIN.gets.chomp&.downcase
48
+ end
49
+ Sequel::Migrator.run(DB, MIGRATIONS_DIR, target: version.to_i)
50
+ end
51
+
52
+ Rake::Task["db:migrate"].enhance do
53
+ Rake::Task["db:version"].invoke
54
+ end
55
+
56
+ Rake::Task["db:rollback"].enhance do
57
+ Rake::Task["db:version"].invoke
58
+ end
59
+
60
+ Shaf::DbTask.new(:reset, description: "Reset the database by deleting all rows in all columns") do
61
+ version = 0
62
+ Sequel::Migrator.run(DB, MIGRATIONS_DIR, target: version)
63
+ Sequel::Migrator.run(DB, MIGRATIONS_DIR)
64
+ end
65
+
66
+ Shaf::DbTask.new(:seed, description: "Seed the Database") do
67
+ ENV['RACK_ENV'] ||= 'development'
68
+ require 'config/bootstrap'
69
+
70
+ if File.exist? "db/seeds.rb"
71
+ require "db/seeds"
72
+ end
73
+
74
+ if Dir.exist? "db/seeds"
75
+ Dir['db/seeds/**/*.rb'].each do |file|
76
+ require file.sub(".rb", "")
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,32 @@
1
+ require 'shaf/tasks'
2
+
3
+ namespace :test do |ns|
4
+ Shaf::TestTask.new(:integration) do |t|
5
+ t.pattern = "spec/integration/**/*_spec.rb"
6
+ end
7
+
8
+ Shaf::TestTask.new(:models) do |t|
9
+ t.pattern = "spec/models/**/*_spec.rb"
10
+ end
11
+
12
+ Shaf::TestTask.new(:serializers) do |t|
13
+ t.pattern = "spec/serializers/**/*_spec.rb"
14
+ end
15
+
16
+ Shaf::TestTask.new(:lib) do |t|
17
+ t.pattern = "spec/lib/**/*_spec.rb"
18
+ end
19
+
20
+ Shaf::TestTask.new(:all) do |t|
21
+ t.pattern = [
22
+ "spec/lib/**/*_spec.rb",
23
+ "spec/models/**/*_spec.rb",
24
+ "spec/serializers/**/*_spec.rb",
25
+ "spec/integration/**/*_spec.rb"
26
+ ]
27
+ end
28
+ end
29
+
30
+ desc "Run all tests"
31
+ task test: 'test:all'
32
+
@@ -7,6 +7,11 @@ module Shaf
7
7
  reg.dup
8
8
  end
9
9
 
10
+ def each
11
+ return all.each unless block_given?
12
+ all.each { |c| yield c }
13
+ end
14
+
10
15
  def size
11
16
  reg.size
12
17
  end
@@ -29,7 +34,7 @@ module Shaf
29
34
 
30
35
  def usage
31
36
  reg.compact.map do |entry|
32
- usage = entry.instance_eval { @usage }
37
+ usage = entry.instance_variable_get(:@usage)
33
38
  usage.respond_to?(:call) ? usage.call : usage
34
39
  end
35
40
  end
@@ -49,7 +54,7 @@ module Shaf
49
54
  end
50
55
 
51
56
  def matching_class?(strings, clazz)
52
- identifiers = clazz.instance_eval { @identifiers }
57
+ identifiers = clazz.instance_variable_get(:@identifiers)
53
58
  return false if strings.size < identifiers.size
54
59
  identifiers.zip(strings).all? { |pattern, str| matching_identifier? str, pattern }
55
60
  end
@@ -62,7 +67,7 @@ module Shaf
62
67
  end
63
68
 
64
69
  def identifier_count(clazz)
65
- clazz.instance_eval { @identifiers }&.size || 0
70
+ clazz.instance_variable_get(:@identifiers)&.size || 0
66
71
  end
67
72
 
68
73
  def init_args(clazz, params)
data/lib/shaf/settings.rb CHANGED
@@ -18,16 +18,32 @@ module Shaf
18
18
  def method_missing(method, *args)
19
19
  load unless defined? @settings
20
20
 
21
- define_singleton_method(method) do
22
- @settings.dig(env.to_s, method.to_s)
21
+ if method.to_s.end_with? "="
22
+ define_setter(method)
23
+ public_send(method, args.first)
24
+ else
25
+ define_getter(method)
26
+ public_send(method)
23
27
  end
24
-
25
- return public_send(method)
26
28
  end
27
29
 
28
30
  def respond_to_missing?(method, include_private = false)
29
31
  return true
30
32
  end
33
+
34
+ def define_getter(method)
35
+ define_singleton_method(method) do
36
+ @settings.dig(env.to_s, method.to_s)
37
+ end
38
+ end
39
+
40
+ def define_setter(method)
41
+ define_singleton_method(method) do |arg|
42
+ key = method[0..-2]
43
+ @settings[env.to_s] ||= {}
44
+ @settings[env.to_s][key] = arg
45
+ end
46
+ end
31
47
  end
32
48
  end
33
49
  end
data/lib/shaf/tasks.rb CHANGED
@@ -1,4 +1,7 @@
1
- require 'shaf/settings'
2
- require 'shaf/tasks/db'
3
- require 'shaf/tasks/test'
1
+ require 'shaf/tasks/test_task'
2
+ require 'shaf/tasks/db_task'
3
+ require 'shaf/tasks/api_doc_task'
4
4
 
5
+ module Shaf
6
+ include Tasks
7
+ end