shaf 0.7.0 → 0.7.1

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 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