shaf 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9123190de71ec1df3a8c53c32a8f7e26a72b42bf6255fe2e0613cd0ee5f15837
4
- data.tar.gz: 53f39cd9d1283771a638a4f1a53f85e79e9f329b0dacb8f7dd3ce08ed54d8199
3
+ metadata.gz: ff5e3dc188a76a89a8b4443f3996e61486a6836b91978b0fae3cd5adb9e88296
4
+ data.tar.gz: bbc13631ee68eeef0b86edd050602b625f001d070a3f704d3915b20ce015149e
5
5
  SHA512:
6
- metadata.gz: 9713237dc988ae3a336016338ad711d59766533a68f88db7bbec9da70ac349906f779abef11cf8e9fb3b3865b652120cc756f8a0bd6558d0a7406405b7122ee6
7
- data.tar.gz: 5f80c980f49450f27e1b17b3a13b1d3b724c43c7ae75c297cce54807b1a2a99920159171be152da6dd0fa6d7c239dd0e1e42d4cd08307c3d91f393f730ec5038
6
+ metadata.gz: 65f87a51936f02635793ecb730d211563950c3953cd08b967094d2586b2b1f8bf725e87b6f100b3a61c45c36070fd3a69f2e6b0916185f9c935ae333b10bd89f
7
+ data.tar.gz: ad411b694fe94039f6577d7e934944054657572feeef49abc4557dec4b726a3e9cd71940ae66cfbe52c6de390cecedfa80d107207e1016d50e5dedda2c524297
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -122,7 +122,7 @@ module Shaf
122
122
  else
123
123
  sub_title << ": " unless sub_title.empty?
124
124
  list.each do |name, comment|
125
- @md[:doc] << "#######{sub_title}#{name.gsub('_', '-')}\n#{comment.to_s}\n"
125
+ @md[:doc] << "#######{sub_title}#{name.tr('_', '-')}\n#{comment.to_s}\n"
126
126
  @md[key][name] = comment.to_s.chomp
127
127
  end
128
128
  end
@@ -19,7 +19,7 @@ module Shaf
19
19
 
20
20
  def call
21
21
  in_project_root do
22
- Generator::Factory.create(*args).call(options)
22
+ Generator::Factory.create(*args, **options).call
23
23
  end
24
24
  rescue StandardError => e
25
25
  raise Command::ArgumentError, e.message
@@ -35,8 +35,12 @@ module Shaf
35
35
  def create_gemfile
36
36
  template_file = File.expand_path('../templates/Gemfile.erb', __FILE__)
37
37
  content = File.read(template_file)
38
- File.write "Gemfile",
39
- ERB.new(content, 0, '%-<>').result
38
+ File.write "Gemfile", erb(content)
39
+ end
40
+
41
+ def erb(content)
42
+ return ERB.new(content, 0, '%-<>').result if RUBY_VERSION < "2.6.0"
43
+ ERB.new(content, 0, trim_mode: '%-<>').result
40
44
  end
41
45
 
42
46
  def copy_templates
data/lib/shaf/errors.rb CHANGED
@@ -64,6 +64,17 @@ module Shaf
64
64
  end
65
65
  end
66
66
 
67
+ class ConflictError
68
+ def http_status
69
+ 409
70
+ end
71
+
72
+ def initialize(msg = nil)
73
+ msg ||= "The request conflicts with another resource"
74
+ super(msg, code: "CONFLICT", title: "Conflicting resource")
75
+ end
76
+ end
77
+
67
78
  class UnsupportedMediaTypeError < ServerError
68
79
  def http_status
69
80
  415
@@ -75,5 +86,16 @@ module Shaf
75
86
  super(msg, code: "UNSUPPORTED_MEDIA_TYPE", title: "Unsupported media type")
76
87
  end
77
88
  end
89
+
90
+ class UnprocessableEntityError
91
+ def http_status
92
+ 422
93
+ end
94
+
95
+ def initialize(msg = nil)
96
+ msg ||= "The server can not process this request"
97
+ super(msg, code: "UNPROCESSABLE_ENTITY", title: "Request can not be processed")
98
+ end
99
+ end
78
100
  end
79
101
  end
@@ -2,43 +2,47 @@ require 'digest'
2
2
 
3
3
  module Shaf
4
4
  module CurrentUser
5
- def self.registered(app)
6
- return unless app.respond_to?(:current_user) && app.current_user
5
+ def self.registered(settings)
6
+ return unless settings.respond_to?(:current_user) && settings.current_user
7
7
 
8
- app.log.info 'Using Shaf::CurrentUser'
9
- app.helpers Helpers
8
+ settings.log.info 'Using Shaf::CurrentUser'
9
+ settings.helpers Helpers
10
10
  end
11
11
 
12
- def lookup_user_with(&block)
13
- unless block_given? && block.respond_to?(:call)
14
- raise ArgumentError, '::lookup_user_with requires a block argument'
15
- end
16
- log.info 'Using custom current_user lookup'
17
- Helpers.lookup_proc = block
12
+ def self.digest(token)
13
+ Digest::SHA256.hexdigest(token) if token
18
14
  end
19
15
  end
20
16
 
21
17
  module Helpers
22
- class << self
23
- attr_accessor :lookup_proc
24
-
25
- def user_lookup(request, token)
26
- return lookup_proc.call(token, request) if lookup_proc
27
- return unless token
28
- digest = Digest::SHA256.hexdigest(token)
29
- User.where(auth_token_digest: digest).first
30
- end
18
+ ERR_MSG = 'The default Shaf implementation of #current_user requires a ' \
19
+ 'User model with a column auth_token_digest'.freeze
20
+
21
+ def auth_token
22
+ header = settings.auth_token_header
23
+ request.env[header]
31
24
  end
32
25
 
33
26
  def current_user
34
27
  return @current_user if defined?(@current_user)
35
- header = settings.auth_token_header
36
- token = request.env[header]
37
- @current_user = Helpers.user_lookup(request, token)
28
+
29
+ return unless check_user_model
30
+ digest = Shaf::CurrentUser.digest(auth_token) || return
31
+ @current_user = User.where(auth_token_digest: digest).first
38
32
  end
39
33
 
40
34
  def authenticated?
41
35
  !current_user.nil?
42
36
  end
37
+
38
+ def authenticate!
39
+ authenticated? || raise(Shaf::Errors::UnauthorizedError)
40
+ end
41
+
42
+ def check_user_model
43
+ return true if defined?(User) && User.columns.include?(:auth_token_digest)
44
+ log.warn ERR_MSG
45
+ false
46
+ end
43
47
  end
44
48
  end
data/lib/shaf/formable.rb CHANGED
@@ -9,10 +9,13 @@ module Shaf
9
9
  getter = "#{f.action}_form"
10
10
 
11
11
  define_singleton_method(getter) { f }
12
- next unless builder.instance_accessor_for? f
12
+ next unless instance_accessor = builder.instance_accessor_for(f)
13
13
 
14
14
  define_method(getter) do
15
- f.dup.tap { |fm| fm.resource = self }
15
+ f.dup.tap do |fm|
16
+ fm.resource = self
17
+ fm.fill! if instance_accessor.prefill?
18
+ end
16
19
  end
17
20
  end
18
21
  end
@@ -3,19 +3,20 @@ require 'shaf/formable/form'
3
3
  module Shaf
4
4
  module Formable
5
5
  class Builder
6
+ InstanceAccessorType = Struct.new(:prefill?)
6
7
  DELEGATES = %i[title name action method type fields].freeze
7
8
 
8
9
  attr_reader :forms
9
10
 
10
11
  def initialize(&block)
11
12
  @forms = []
12
- @instance_accessors = []
13
+ @instance_accessors = {}
13
14
 
14
15
  exec_with_form(block)
15
16
  end
16
17
 
17
- def instance_accessor_for?(form)
18
- @instance_accessors.include? form
18
+ def instance_accessor_for(form)
19
+ @instance_accessors[form.action]
19
20
  end
20
21
 
21
22
  private
@@ -34,8 +35,9 @@ module Shaf
34
35
  (form&.dup || Formable::Form.new).tap { |f| @forms << f }
35
36
  end
36
37
 
37
- def instance_accessor
38
- @instance_accessors << form
38
+ def instance_accessor(prefill: true)
39
+ acc = InstanceAccessorType.new(prefill)
40
+ @instance_accessors[form.action] = acc
39
41
  end
40
42
 
41
43
  DELEGATES.each do |name|
@@ -5,7 +5,7 @@ module Shaf
5
5
  class Field
6
6
  extend Shaf::ImmutableAttr
7
7
 
8
- immutable_reader :name, :type, :value, :label, :required
8
+ immutable_reader :name, :type, :value, :label, :required, :accessor_name
9
9
 
10
10
  HTML_TYPE_MAPPINGS = {
11
11
  string: 'text',
@@ -19,12 +19,18 @@ module Shaf
19
19
  @has_value = params.key? :value
20
20
  @value = params[:value]
21
21
  @required = params[:required] || false
22
+ @accessor_name = (params[:accessor_name] || name).to_sym
22
23
  end
23
24
 
24
25
  def has_value?
25
26
  @has_value
26
27
  end
27
28
 
29
+ def value=(v)
30
+ @value = v
31
+ @has_value = true
32
+ end
33
+
28
34
  def to_html
29
35
  [
30
36
  '<div class="form--input-group">',
@@ -6,6 +6,8 @@ module Shaf
6
6
  class Form
7
7
  extend Shaf::ImmutableAttr
8
8
 
9
+ class FormHasNoResourceError < Shaf::Error; end
10
+
9
11
  DEFAULT_TYPE = 'application/json'.freeze
10
12
 
11
13
  attr_accessor :resource
@@ -15,7 +17,7 @@ module Shaf
15
17
  def initialize(params = {})
16
18
  @title = params[:title]
17
19
  @action = params[:action]
18
- @name = params[:name] || name_from(@action)
20
+ @name = params[:name]&.to_sym || name_from(@action)
19
21
  @method = params[:method] ||= http_method_from(@action)
20
22
  @type = params[:type] || DEFAULT_TYPE
21
23
  @fields = (params[:fields] || {}).map do |name, args|
@@ -56,6 +58,19 @@ module Shaf
56
58
  dup.tap { |obj| obj.freeze if frozen? }
57
59
  end
58
60
 
61
+ def fill!(from: nil)
62
+ resrc = from || resource
63
+ raise FormHasNoResourceError, <<~MSG unless resrc
64
+ Trying to fill form with values from resource, but form '#{name}' has no resource!
65
+ MSG
66
+
67
+ fields.each do |field|
68
+ accessor_name = field.accessor_name
69
+ next unless resrc.respond_to? accessor_name
70
+ field.value = resrc.send(accessor_name)
71
+ end
72
+ end
73
+
59
74
  def to_html
60
75
  form_element do
61
76
  [
@@ -5,7 +5,7 @@ require 'ostruct'
5
5
  module Shaf
6
6
  module Generator
7
7
  class Base
8
- attr_reader :args
8
+ attr_reader :args, :options
9
9
 
10
10
  class << self
11
11
  def inherited(child)
@@ -23,11 +23,12 @@ module Shaf
23
23
  def options(option_parser, options); end
24
24
  end
25
25
 
26
- def initialize(*args)
27
- @args = args.dup
26
+ def initialize(*args, **options)
27
+ @args = args
28
+ @options = options
28
29
  end
29
30
 
30
- def call(options = {}); end
31
+ def call; end
31
32
 
32
33
  def template_dir
33
34
  File.expand_path('../templates', __FILE__)
@@ -44,7 +45,9 @@ module Shaf
44
45
  str = read_template(template)
45
46
  locals[:changes] ||= []
46
47
  b = OpenStruct.new(locals).instance_eval { binding }
47
- ERB.new(str, 0, '%-<>').result(b)
48
+
49
+ return ERB.new(str, 0, '%-<>').result(b) if RUBY_VERSION < "2.6.0"
50
+ ERB.new(str, 0, trim_mode: '%-<>').result(b)
48
51
  rescue SystemCallError => e
49
52
  puts "Failed to render template #{template}: #{e.message}"
50
53
  raise
@@ -5,7 +5,7 @@ module Shaf
5
5
  identifier :controller
6
6
  usage 'generate controller RESOURCE_NAME [attribute:type] [..]'
7
7
 
8
- def call(options = {})
8
+ def call
9
9
  create_controller
10
10
  create_integration_spec if options[:specs]
11
11
  add_link_to_root
@@ -11,7 +11,7 @@ module Shaf
11
11
  usage { Factory.usage }
12
12
 
13
13
  def call
14
- generator = args.empty? ? Empty.new : Factory.create(*args)
14
+ generator = args.empty? ? Empty.new(**options) : Factory.create(*args, **options)
15
15
  (target, content) = generator.call
16
16
  write_output(target, content)
17
17
  rescue StandardError => e
@@ -32,7 +32,7 @@ module Shaf
32
32
  }
33
33
  ]
34
34
 
35
- attr_reader :args
35
+ attr_reader :args, :options
36
36
 
37
37
  class << self
38
38
  def inherited(child)
@@ -48,8 +48,9 @@ module Shaf
48
48
  end
49
49
  end
50
50
 
51
- def initialize(*args)
52
- @args = args.dup
51
+ def initialize(*args, **options)
52
+ @args = args
53
+ @options = options
53
54
  end
54
55
 
55
56
  def call
@@ -5,10 +5,10 @@ module Shaf
5
5
  identifier :model
6
6
  usage 'generate model MODEL_NAME [attribute:type] [..]'
7
7
 
8
- def call(options = {})
8
+ def call
9
9
  create_model
10
10
  create_migration
11
- create_serializer(options)
11
+ create_serializer
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(options)
64
+ def create_serializer
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(options)
67
+ Generator::Factory.create(*serializer_args, **options).call
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(options = {})
7
+ def call
8
8
  create_policy
9
9
  end
10
10
 
@@ -5,14 +5,14 @@ module Shaf
5
5
  identifier :scaffold
6
6
  usage 'generate scaffold RESOURCE_NAME [attribute:type] [..]'
7
7
 
8
- def call(options = {})
8
+ def call
9
9
  if name.empty?
10
10
  raise "Please provide a resource name when using the scaffold generator!"
11
11
  end
12
12
 
13
13
  options[:specs] = true if options[:specs].nil?
14
- Generator::Factory.create('model', *args).call(options)
15
- Generator::Factory.create('controller', *controller_args).call(options)
14
+ Generator::Factory.create('model', *args, **options).call
15
+ Generator::Factory.create('controller', *controller_args, **options).call
16
16
  end
17
17
 
18
18
  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(options = {})
7
+ def call
8
8
  create_serializer
9
9
  create_serializer_spec if options[:specs]
10
- create_policy(options)
10
+ create_policy
11
11
  end
12
12
 
13
13
  def name
@@ -211,9 +211,9 @@ module Shaf
211
211
  }
212
212
  end
213
213
 
214
- def create_policy(options)
214
+ def create_policy
215
215
  policy_args = ["policy", name, *args[1..-1]]
216
- Generator::Factory.create(*policy_args).call(options)
216
+ Generator::Factory.create(*policy_args, **options).call
217
217
  end
218
218
  end
219
219
  end
@@ -10,7 +10,7 @@ class <%= policy_class_name %> < BasePolicy
10
10
 
11
11
  link :up
12
12
 
13
- link :edit, :'create-form', :'edit-form', :delete do
13
+ link :'create-form', :'edit-form', :delete do
14
14
  write?
15
15
  end
16
16
 
data/lib/shaf/spec.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'shaf/spec/http_method_utils'
2
2
  require 'shaf/spec/payload_utils'
3
3
  require 'shaf/spec/fixture'
4
+ require 'shaf/spec/let_bang'
4
5
  require 'shaf/spec/base'
5
6
  require 'shaf/spec/integration_spec'
6
7
  require 'shaf/spec/serializer_spec'
8
+ require 'shaf/spec/system_spec'
@@ -2,8 +2,9 @@ module Shaf
2
2
  module Spec
3
3
  class Base < Minitest::Spec
4
4
  include Minitest::Hooks
5
- include PayloadUtils
6
5
  include Fixtures::Accessors
6
+ include UriHelper
7
+ include LetBang
7
8
 
8
9
  TRANSACTION_OPTIONS = {
9
10
  rollback: :always,
@@ -29,6 +30,8 @@ module Shaf
29
30
  # #{self.class.superclass.name} - #{name}
30
31
  ##########################################################################
31
32
  LOG
33
+
34
+ let_bangs.each { |name| send(name) }
32
35
  end
33
36
  end
34
37
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shaf
2
4
  module Spec
3
5
  class IntegrationSpec < Base
6
+ include PayloadUtils
4
7
  include HttpUtils
5
- include UriHelper
6
8
 
7
9
  register_spec_type self do |desc, args|
8
10
  next unless args && args.is_a?(Hash)
@@ -0,0 +1,31 @@
1
+ require 'set'
2
+
3
+ module LetBang
4
+ module ClassMethods
5
+ def let!(name, &block)
6
+ return unless respond_to? :let
7
+ let(name, &block)
8
+ let_bangs << name
9
+ end
10
+
11
+ def let_bangs
12
+ @let_bangs ||= Set.new
13
+ end
14
+ end
15
+
16
+ def self.included(base)
17
+ base.extend ClassMethods
18
+ end
19
+
20
+ def let_bangs
21
+ klass = self.class
22
+ Set.new.tap do |bangs|
23
+ loop do
24
+ bangs.merge(klass.let_bangs) if klass.respond_to? :let_bangs
25
+ klass = klass.superclass
26
+ break if Object == klass
27
+ end
28
+ end
29
+ end
30
+ end
31
+
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shaf
2
4
  module Spec
3
5
  class SerializerSpec < Base
6
+ include PayloadUtils
7
+
4
8
  register_spec_type self do |desc, args|
5
9
  next true if desc.to_s =~ /Serializer$/
6
10
  next unless args && args.is_a?(Hash)
@@ -8,7 +12,18 @@ module Shaf
8
12
  end
9
13
 
10
14
  def serialize(resource, current_user:)
11
- set_payload HALPresenter.to_hal(resource, current_user: current_user)
15
+ serializer = __serializer || HALPresenter
16
+ set_payload serializer.to_hal(resource, current_user: current_user)
17
+ end
18
+
19
+ private
20
+
21
+ def __serializer
22
+ serializer = self.class.ancestors.find do |klass|
23
+ desc = klass.desc if klass.respond_to? :desc
24
+ break desc if desc&.to_s&.end_with? "Serializer"
25
+ end
26
+ Class === serializer ? serializer : Kernel.const_get(serializer.to_s)
12
27
  end
13
28
  end
14
29
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shaf
4
+ module Spec
5
+ class SystemSpec < Base
6
+ register_spec_type self do |desc, args|
7
+ next unless args && args.is_a?(Hash)
8
+ args[:type]&.to_s == 'system'
9
+ end
10
+ end
11
+ end
12
+ end
13
+
data/lib/shaf/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Shaf
2
- VERSION = "0.7.0"
2
+ VERSION = "0.7.1"
3
3
  end
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: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sammy Henningsson
@@ -30,7 +30,7 @@ cert_chain:
30
30
  ZMhjYR7sRczGJx+GxGU2EaR0bjRsPVlC4ywtFxoOfRG3WaJcpWGEoAoMJX6Z0bRv
31
31
  M40=
32
32
  -----END CERTIFICATE-----
33
- date: 2018-11-24 00:00:00.000000000 Z
33
+ date: 2019-01-05 00:00:00.000000000 Z
34
34
  dependencies:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: rake
@@ -182,10 +182,12 @@ files:
182
182
  - lib/shaf/spec/fixtures.rb
183
183
  - lib/shaf/spec/http_method_utils.rb
184
184
  - lib/shaf/spec/integration_spec.rb
185
+ - lib/shaf/spec/let_bang.rb
185
186
  - lib/shaf/spec/model.rb
186
187
  - lib/shaf/spec/payload_test.rb
187
188
  - lib/shaf/spec/payload_utils.rb
188
189
  - lib/shaf/spec/serializer_spec.rb
190
+ - lib/shaf/spec/system_spec.rb
189
191
  - lib/shaf/tasks.rb
190
192
  - lib/shaf/tasks/api_doc_task.rb
191
193
  - lib/shaf/tasks/db_task.rb
@@ -249,8 +251,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
249
251
  - !ruby/object:Gem::Version
250
252
  version: '0'
251
253
  requirements: []
252
- rubyforge_project:
253
- rubygems_version: 2.7.6
254
+ rubygems_version: 3.0.1
254
255
  signing_key:
255
256
  specification_version: 4
256
257
  summary: Sinatra Hypermedia Api Framework
metadata.gz.sig CHANGED
Binary file