doc_contract 0.1.6 → 0.2.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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -2
  3. data/Rakefile +6 -5
  4. data/app/assets/javascripts/doc_contract/application.coffee +2 -0
  5. data/app/controllers/concerns/doc_contract/shared_template_and_instance_methods.rb +24 -7
  6. data/app/controllers/doc_contract/application_controller.rb +4 -1
  7. data/app/controllers/doc_contract/contract_instances_controller.rb +14 -12
  8. data/app/controllers/doc_contract/contract_templates_controller.rb +14 -25
  9. data/app/helpers/doc_contract/application_helper.rb +38 -17
  10. data/app/models/concerns/yaml_validator.rb +9 -3
  11. data/app/models/doc_contract/application_record.rb +27 -0
  12. data/app/models/doc_contract/contract_instance.rb +9 -2
  13. data/app/models/doc_contract/contract_template.rb +14 -3
  14. data/app/views/doc_contract/application/_button-preview-pdf.html.slim +1 -1
  15. data/app/views/doc_contract/application/_navigation.html.slim +7 -3
  16. data/app/views/doc_contract/application/main.html.slim +1 -1
  17. data/app/views/doc_contract/contract_instances/_form.html.slim +4 -1
  18. data/config/environment.rb +4 -0
  19. data/config/initializers/human_plural.rb +8 -5
  20. data/config/routes.rb +3 -2
  21. data/db/migrate/20220118150923_create_doc_contract_contract_templates.rb +1 -0
  22. data/db/migrate/20220121160034_add_markdown_to_doc_contract_contract_templates.rb +1 -0
  23. data/db/migrate/20220121165825_add_config_yml_to_doc_contract_contract_templates.rb +1 -0
  24. data/db/migrate/20220122151402_create_doc_contract_contract_instances.rb +1 -0
  25. data/db/migrate/20220125183437_add_titlepage_background_to_contract_templates.rb +1 -0
  26. data/lib/doc_contract/engine.rb +25 -10
  27. data/lib/doc_contract/handlebars.rb +45 -30
  28. data/lib/doc_contract/version.rb +3 -1
  29. data/lib/doc_contract.rb +4 -3
  30. data/lib/tasks/doc_contract_tasks.rake +1 -0
  31. metadata +17 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10539557dfc2459c982fd3f6eb174e5012e5d7db7cf4001a38f684ce96d758cb
4
- data.tar.gz: 5417b3780907dacd938cbb937b87381b1218ac839fcbfe7f6f6a6611ff08f006
3
+ metadata.gz: a3a6c918f368226c070e81509c178e61d83f45cd1f239a126ae66a355f50c512
4
+ data.tar.gz: 7bb72324e156c3fc3451e7379b9ab642ce395808ca0d3c2117819fd0231a86c8
5
5
  SHA512:
6
- metadata.gz: 9fa4bb103d56400fd0599ccba7a20e475583ea704e7bcf20eb306960aa0d82b29c86f5e83cbcba6f38caaa3a76643000f9c1f04308148f5fa98d2344d9c4548d
7
- data.tar.gz: 431cb7417342a0ff44f31040ec78f2dd7798882d5bedfb29159fc4ac8795f726de11fa5063b4e9209fe015c0cf951f12eb86c2579731681b4d7dd3451526ae0a
6
+ metadata.gz: 23ab0131768cc5d6579447c141de09915656d3d1249d8f966f1e55daa8b455189e3d4793ef995169ddf56aecceea914826bbf2156277f301974762229a1821b1
7
+ data.tar.gz: 76096e9d5a43835fd96dd94ca9a5ddc75b85ab12c3ceb60c3e66655a55404e05d5fcdc6d9cd97105b631c4d88acbda606b8c06710d266c44af56b4b3d3596ea5
data/README.md CHANGED
@@ -173,16 +173,17 @@ To put your own version of this page create a view having this path in the main
173
173
  put the following in your `config/application.rb` file:
174
174
 
175
175
  ```ruby
176
- config.doc_contract.show_readme_on_main_page = false
176
+ config.x.doc_contract.show_readme_on_main_page = false
177
177
  ```
178
178
 
179
179
  ### The link home content
180
180
  The default value for `config/application.rb` is:
181
181
 
182
182
  ```ruby
183
- config.doc_contract.link_home_content = '<i class="arrow left icon"></i> Back'
183
+ config.x.doc_contract.link_home_content = -> { '<i class="arrow left icon"></i> Back' }
184
184
  ```
185
185
  To change for example the icon, see the options at the [fomantic-ui](https://fomantic-ui.com/elements/icon.html) site.
186
+ Note that the value is a `lambda` to allow the use of for example `I18n`.
186
187
 
187
188
  ### Screenshot
188
189
  ![Edit template scnreenshot](/spec/dummy/public/DocContract-template-edit.png)
data/Rakefile CHANGED
@@ -1,8 +1,9 @@
1
- require "bundler/setup"
1
+ # frozen_string_literal: true
2
+ require 'bundler/setup'
2
3
 
3
- APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
4
- load "rails/tasks/engine.rake"
4
+ APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
5
+ load 'rails/tasks/engine.rake'
5
6
 
6
- load "rails/tasks/statistics.rake"
7
+ load 'rails/tasks/statistics.rake'
7
8
 
8
- require "bundler/gem_tasks"
9
+ require 'bundler/gem_tasks'
@@ -11,6 +11,8 @@ latex_template_infos =
11
11
  </a>'
12
12
  $ ->
13
13
  $('.ui.dropdown').dropdown() # assume fomantic that has the clearable class option, a lot better than the below custom code
14
+ $('.message .close').on 'click', ->
15
+ $(@).closest('.message').transition('fade')
14
16
 
15
17
  $('.preview-markdown').click ->
16
18
  markdown = $('#contract_template_markdown').val()
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module DocContract
2
3
  module SharedTemplateAndInstanceMethods
3
4
  # POST /doc-contract/contract_templates/:id/processed_markdown?markdown=...
@@ -19,12 +20,17 @@ module DocContract
19
20
  render json: {html: @record.processed_html}
20
21
  end
21
22
 
22
- def get_pdf
23
+ # rubocop:disable Metrics/MethodLength
24
+ # for now keep as a whole story
25
+ def pdf
23
26
  @record = record_class.find params[:id]
24
27
  authorize! :show, @record
28
+
25
29
  # Allow preview using the markdown parameter. Fallback to actual saved
26
30
  # version when param is not given
27
31
  @record.markdown = params[:markdown] if params[:markdown].present?
32
+ return redirect_to @record unless @record.markdown.present?
33
+
28
34
  @tempfile_markdown = Tempfile.new(['pandoc-markdown', '.md'])
29
35
  config_addittions = {}
30
36
  if nbackground = @record.try(:titlepage_background) || @record.contract_template.titlepage_background.presence
@@ -36,31 +42,42 @@ module DocContract
36
42
  @tempfile_markdown.close
37
43
  @tempfile_pdf = Tempfile.create(['pandoc-pdf-', '.pdf'])
38
44
  @tempfile_pdf.close
39
- command = %( pandoc --template=vendor/assets/doc-contract/pandoc-templates/eisvogel.tex --css=app/assets/stylesheets/doc_contract/pandoc.css #{@tempfile_markdown.path} -o #{@tempfile_pdf.path} )
40
- command << " --variable top-level-division=chapter" if @record.config['book']
45
+ command = %(
46
+ pandoc --template=vendor/assets/doc-contract/pandoc-templates/eisvogel.tex
47
+ --css=app/assets/stylesheets/doc_contract/pandoc.css #{@tempfile_markdown.path}
48
+ -o #{@tempfile_pdf.path}
49
+ ).strip.gsub(/\n\s*/, ' ')
50
+ command << ' --variable top-level-division=chapter' if @record.config['book']
41
51
  #command << " --variable titlepage=true" if false # done through YAML config
42
- command << " --listings" # if some conditions TODO: make this a database boolean
43
- command << " --filter pandoc-latex-environment" if template_markdown['pandoc-latex-environment:']
52
+ command << ' --listings' # if some conditions TODO: make this a database boolean
53
+ command << ' --filter pandoc-latex-environment' if template_markdown['pandoc-latex-environment:']
44
54
 
45
55
  stdout, stderr, status = nil
46
56
  Dir.chdir DocContract::Engine.root do
47
57
  stdout, stderr, status = Open3.capture3(command)
48
58
  end
59
+
49
60
  if status.success?
50
61
  send_file @tempfile_pdf.path
51
62
  else
52
63
  redirect_back fallback_location: record_class, flash: {error: stderr}
53
64
  end
54
65
  ensure
55
- @tempfile_markdown.unlink rescue nil
56
- @tempfile_pdf.unlink rescue nil
66
+ begin
67
+ @tempfile_markdown.unlink
68
+ @tempfile_pdf.unlink
69
+ rescue
70
+ nil
71
+ end
57
72
  end
73
+ # rubocop:enable Metrics/MethodLength
58
74
 
59
75
  private
60
76
 
61
77
  def record_class
62
78
  result = controller_path.classify.safe_constantize
63
79
  raise "Cannot determine record_class from controller_path: #{controller_path}" unless result
80
+
64
81
  result
65
82
  end
66
83
 
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DocContract
2
- class ApplicationController < ApplicationController
4
+ class ApplicationController < ::ApplicationController
3
5
  helper_method :query, :readme_html
4
6
 
5
7
  def main
8
+ # root landing action
6
9
  end
7
10
 
8
11
  private
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module DocContract
2
3
  class ContractInstancesController < ApplicationController
3
4
  include SharedTemplateAndInstanceMethods
@@ -14,16 +15,12 @@ module DocContract
14
15
 
15
16
  def new
16
17
  @record = record_class.new
17
- end
18
-
19
- def edit
20
- @record = record_class.find(params[:id])
21
- authorize! :edit, @record
18
+ authorize! :create, @record
22
19
  end
23
20
 
24
21
  def create
25
- authorize! :create, record_class
26
22
  @record = record_class.new record_params
23
+ authorize! :create, @record
27
24
  if @record.save
28
25
  redirect_to @record
29
26
  else
@@ -31,9 +28,19 @@ module DocContract
31
28
  end
32
29
  end
33
30
 
31
+ def show
32
+ @record = record_class.find params[:id]
33
+ authorize! :show, @record
34
+ end
35
+
36
+ def edit
37
+ @record = record_class.find(params[:id])
38
+ authorize! :edit, @record
39
+ end
40
+
34
41
  def update
35
42
  @record = record_class.find params[:id]
36
- authorize! :update, @record
43
+ authorize! :edit, @record
37
44
  if @record.update record_params
38
45
  redirect_to @record
39
46
  else
@@ -41,11 +48,6 @@ module DocContract
41
48
  end
42
49
  end
43
50
 
44
- def show
45
- @record = record_class.find params[:id]
46
- authorize! :show, @record
47
- end
48
-
49
51
  def destroy
50
52
  @record = record_class.find params[:id]
51
53
  authorize! :destroy, @record
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module DocContract
2
3
  class ContractTemplatesController < ApplicationController
3
4
  include SharedTemplateAndInstanceMethods
@@ -14,16 +15,12 @@ module DocContract
14
15
 
15
16
  def new
16
17
  @record = record_class.new
17
- end
18
-
19
- def edit
20
- @record = record_class.find(params[:id])
21
- authorize! :edit, @record
18
+ authorize! :create, @record
22
19
  end
23
20
 
24
21
  def create
25
- authorize! :create, record_class
26
22
  @record = record_class.new record_params
23
+ authorize! :create, @record
27
24
  if @record.save
28
25
  redirect_to @record, status: :see_other
29
26
  else
@@ -31,9 +28,19 @@ module DocContract
31
28
  end
32
29
  end
33
30
 
31
+ def show
32
+ @record = record_class.find params[:id]
33
+ authorize! :show, @record
34
+ end
35
+
36
+ def edit
37
+ @record = record_class.find(params[:id])
38
+ authorize! :edit, @record
39
+ end
40
+
34
41
  def update
35
42
  @record = record_class.find params[:id]
36
- authorize! :update, @record
43
+ authorize! :edit, @record
37
44
  if @record.update record_params
38
45
  redirect_to @record, status: :see_other
39
46
  else
@@ -41,29 +48,11 @@ module DocContract
41
48
  end
42
49
  end
43
50
 
44
- def show
45
- @record = record_class.find params[:id]
46
- authorize! :show, @record
47
- end
48
-
49
51
  def destroy
50
52
  @record = record_class.find params[:id]
51
53
  authorize! :destroy, @record
52
54
  @record.destroy
53
55
  redirect_to record_class, status: :see_other
54
56
  end
55
-
56
- private
57
-
58
- def record_class
59
- result = controller_path.classify.safe_constantize
60
- raise "Cannot determine record_class from controller_path: #{controller_path}" unless result
61
-
62
- result
63
- end
64
-
65
- def record_params
66
- params.require(record_class.name.demodulize.underscore).permit!
67
- end
68
57
  end
69
58
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DocContract
2
4
  module ApplicationHelper
3
5
  # Return active or nil based on the given route spec
@@ -6,8 +8,9 @@ module DocContract
6
8
  #NOTE: Taken from the dunlop-core gem. That is the best maintained version
7
9
  def active_class(*route_specs)
8
10
  options = route_specs.extract_options!
9
- return nil if Array.wrap(options[:except]).any?{|exception| current_route_spec?(exception) }
10
- return 'active' if route_specs.any?{|rs| current_route_spec?(rs, options) }
11
+ return nil if Array.wrap(options[:except]).any?{ |exception| current_route_spec?(exception) }
12
+ return 'active' if route_specs.any?{ |rs| current_route_spec?(rs, options) }
13
+
11
14
  nil
12
15
  end
13
16
 
@@ -19,17 +22,21 @@ module DocContract
19
22
  # current_route_spec?('#show') #=> true if action_name is show, false otherwise
20
23
  #NOTE: this helper is tested through the active_class helper
21
24
  #NOTE: Taken from the dunlop-core gem. That is the best maintained version
22
- def current_route_spec?(route_spec, options = {})
25
+ def current_route_spec?(route_spec, _options = {})
23
26
  return route_spec.match([controller_path, action_name].join('#')) if route_spec.is_a?(Regexp)
27
+
24
28
  controller, action = route_spec.split('#')
25
29
  return action == params[:id] if controller_path == 'high_voltage/pages'
30
+
26
31
  actual_controller_parts = controller_path.split('/')
27
32
  if controller #and controller_path == controller
28
33
  tested_controller_parts = controller.split('/')
29
34
  return if tested_controller_parts.size > actual_controller_parts.size
35
+
30
36
  if actual_controller_parts[0...tested_controller_parts.size] == tested_controller_parts
31
37
  # controller spec matches
32
38
  return true unless action
39
+
33
40
  action_name == action
34
41
  end
35
42
  else
@@ -78,11 +85,11 @@ module DocContract
78
85
  def page_title_for_resource(args)
79
86
  options = args.extract_options!
80
87
  model = args[1].respond_to?(:model_name) ? args[1] : args[1].class
81
- if args.first == :index
82
- title = t('action.index.label', models: model.model_name.human_plural).html_safe
83
- else
84
- title = t("action.#{args.first}.label", model: model.model_name.human).html_safe
85
- end
88
+ title = if args.first == :index
89
+ t('action.index.label', models: model.model_name.human_plural).html_safe
90
+ else
91
+ t("action.#{args.first}.label", model: model.model_name.human).html_safe
92
+ end
86
93
  if back_options = options[:back]
87
94
  url =
88
95
  case back_options
@@ -105,7 +112,7 @@ module DocContract
105
112
  "#{from_item} - #{to_item} / #{records.total_count}"
106
113
  end
107
114
 
108
- def at(attribute_name, scope_model=nil)
115
+ def at(attribute_name, scope_model = nil)
109
116
  scope_model ||= @scope_model
110
117
  scope_model.human_attribute_name(attribute_name)
111
118
  end
@@ -116,7 +123,7 @@ module DocContract
116
123
  classes |= ['search']
117
124
  classes << 'conditions-present' if @q.conditions.present?
118
125
  content = capture(&blk)
119
- content_tag(:tr, content, class: classes )
126
+ content_tag(:tr, content, class: classes)
120
127
  end
121
128
 
122
129
  # This helper returns the link for showing a record inside a table
@@ -126,7 +133,11 @@ module DocContract
126
133
  else
127
134
  return unless can? :show, record
128
135
  end
129
- link_to(content_tag(:i,nil, class: 'folder open icon'), path || record, class: 'table-link show ui mini basic primary icon button')
136
+ link_to(
137
+ content_tag(:i, nil, class: 'folder open icon'),
138
+ path || record,
139
+ class: 'table-link show ui mini basic primary icon button'
140
+ )
130
141
  end
131
142
 
132
143
  # This helper returns the link for showing a record inside a table
@@ -136,7 +147,11 @@ module DocContract
136
147
  else
137
148
  return unless can? :download, record
138
149
  end
139
- link_to(content_tag(:i,nil, class: 'download icon'), path || [:download, record], class: 'table-link download ui mini violet icon button')
150
+ link_to(
151
+ content_tag(:i, nil, class: 'download icon'),
152
+ path || [:download, record],
153
+ class: 'table-link download ui mini violet icon button'
154
+ )
140
155
  end
141
156
 
142
157
  # This helper returns the link for editing a record inside a table
@@ -161,16 +176,22 @@ module DocContract
161
176
  record_name ||= record.name if record.respond_to?(:name)
162
177
  record_name ||= record.title if record.respond_to?(:title)
163
178
  confirm_text << " #{record_name}" if record_name.present?
164
- confirm_text << "?"
165
- link_to(content_tag(:i, nil, class: 'trash icon'), path || record, method: :delete, data: { confirm: confirm_text }, class: 'table-link destroy ui mini negative icon button')
179
+ confirm_text << '?'
180
+ link_to(
181
+ content_tag(:i, nil, class: 'trash icon'),
182
+ path || record,
183
+ method: :delete,
184
+ data: { confirm: confirm_text },
185
+ class: 'table-link destroy ui mini negative icon button'
186
+ )
166
187
  end
167
188
 
168
189
  # https://coderwall.com/p/7gqmog/display-flash-messages-with-semantic-ui-in-rails
169
190
  def flash_class(level)
170
191
  case level.to_sym
171
- when :success then "ui positive message"
172
- when :error, :alert then "ui negative message"
173
- when :notice then "ui info message"
192
+ when :success then 'ui positive message'
193
+ when :error, :alert then 'ui negative message'
194
+ when :notice then 'ui info message'
174
195
  else "ui #{level} message"
175
196
  end
176
197
  end
@@ -1,9 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class YamlValidator < ActiveModel::EachValidator
2
4
  def validate_each(record, attribute, value)
3
5
  return if value.blank?
4
- object = YAML.load(value) rescue nil
5
- unless object
6
- record.errors.add attribute, (options[:message] || "is not valid YAML")
6
+
7
+ object = begin
8
+ YAML.safe_load(value, permitted_classes: [Symbol, Date])
9
+ rescue # Psych::SyntaxError
10
+ nil
7
11
  end
12
+
13
+ record.errors.add attribute, (options[:message] || 'is not valid YAML') unless object
8
14
  end
9
15
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DocContract
4
+ class ApplicationRecord < ActiveRecord::Base
5
+
6
+ self.abstract_class = true
7
+
8
+ RANSACKABLE_ATTRIBUTES = [].freeze
9
+ RANSACKABLE_ASSOCIATIONS = [].freeze
10
+
11
+ def self.ransackable_attributes(_auth_object = nil)
12
+ if const_defined? :RANSACKABLE_ATTRIBUTES
13
+ const_get :RANSACKABLE_ATTRIBUTES
14
+ else
15
+ RANSACKABLE_ATTRIBUTES
16
+ end
17
+ end
18
+
19
+ def self.ransackable_associations(_auth_object = nil)
20
+ if const_defined? :RANSACKABLE_ASSOCIATIONS
21
+ const_get :RANSACKABLE_ASSOCIATIONS
22
+ else
23
+ RANSACKABLE_ASSOCIATIONS
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,8 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DocContract
2
4
  class ContractInstance < ApplicationRecord
3
- validates :name, presence: true
5
+
4
6
  belongs_to :contract_template
5
7
 
8
+ validates :name, presence: true
9
+
10
+ RANSACKABLE_ATTRIBUTES = %w[name].freeze
11
+ RANSACKABLE_ASSOCIATIONS = %w[contract_template].freeze
12
+
6
13
  def config
7
14
  own_config = YAML.safe_load(config_yml.to_s, permitted_classes: [Symbol, Date]) || {}
8
15
  own_config.reverse_merge contract_template.config
@@ -27,7 +34,7 @@ module DocContract
27
34
  config.merge! config_addittions unless config_addittions.blank?
28
35
  result = DocContract::Handlebars.compile(markdown, config)
29
36
  # prefix the markdown with the config (eisvogel pandoc)
30
- "#{config.to_yaml}...\n\n"+result
37
+ "#{config.to_yaml}...\n\n#{result}"
31
38
  end
32
39
 
33
40
  def processed_html
@@ -1,6 +1,12 @@
1
+ # frozen_string_literal: true
1
2
  module DocContract
2
3
  class ContractTemplate < ApplicationRecord
3
- HANDLEBARS_REGEX = /{{((#)?[a-z\._ ]+)}}/
4
+
5
+ HANDLEBARS_REGEX = /{{((#)?[a-z._ ]+)}}/
6
+
7
+ RANSACKABLE_ATTRIBUTES = %w[name].freeze
8
+ #RANSACKABLE_ASSOCIATIONS = %w[].freeze
9
+
4
10
  has_many :contract_instances, dependent: :delete_all
5
11
 
6
12
  validates :name, presence: true
@@ -10,6 +16,11 @@ module DocContract
10
16
  YAML.safe_load(config_yml.to_s, permitted_classes: [Symbol, Date]) || {}
11
17
  end
12
18
 
19
+ # Do not fail when an instance trait tries to access fallback template properties
20
+ def contract_template
21
+ self
22
+ end
23
+
13
24
  def processed_markdown(config_addittions = {})
14
25
  config = self.config
15
26
  config.merge! config_addittions unless config_addittions.blank?
@@ -21,7 +32,7 @@ module DocContract
21
32
  config.merge! config_addittions unless config_addittions.blank?
22
33
  result = DocContract::Handlebars.compile(markdown, config)
23
34
  # prefix the markdown with the config (eisvogel pandoc)
24
- "#{config.to_yaml}...\n\n"+result
35
+ "#{config.to_yaml}...\n\n#{result}"
25
36
  end
26
37
 
27
38
  def processed_html
@@ -31,7 +42,7 @@ module DocContract
31
42
  end
32
43
 
33
44
  def present_handlebars_expressions
34
- markdown.scan(HANDLEBARS_REGEX).map(&:first).uniq
45
+ markdown.to_s.scan(HANDLEBARS_REGEX).map(&:first).uniq
35
46
  end
36
47
  end
37
48
  end
@@ -1 +1 @@
1
- = link_to 'PDF', polymorphic_path(@record, action: :get_pdf), class: 'ui button'
1
+ = link_to 'PDF', polymorphic_path(@record, action: :pdf), class: 'ui button'
@@ -1,9 +1,13 @@
1
1
  .ui.inverted.menu.fixed
2
2
  = link_to main_app.root_path, class: 'header item'
3
- = Rails.application.config.doc_contract.link_home_content.to_s.html_safe
3
+ = Rails.application.config.x.doc_contract.link_home_content.call.to_s.html_safe
4
+ = link_to doc_contract.root_path, class: 'header item'
5
+ = Rails.application.config.x.doc_contract.application_title.call.to_s.html_safe
4
6
  - if current_user.present?
5
- = link_to DocContract::ContractTemplate.model_name.human_plural, [DocContract::ContractTemplate], class: ['item', active_class('doc_contract/contract_templates')]
6
- = link_to DocContract::ContractInstance.model_name.human_plural, [DocContract::ContractInstance], class: ['item', active_class('doc_contract/contract_instances')]
7
+ - if can? :read, DocContract::ContractTemplate
8
+ = link_to DocContract::ContractTemplate.model_name.human_plural, [DocContract::ContractTemplate], class: ['item', active_class('doc_contract/contract_templates')]
9
+ - if can? :read, DocContract::ContractInstance
10
+ = link_to DocContract::ContractInstance.model_name.human_plural, [DocContract::ContractInstance], class: ['item', active_class('doc_contract/contract_instances')]
7
11
  .right.menu
8
12
  - if current_user.present?
9
13
  .ui.dropdown.item
@@ -1,6 +1,6 @@
1
1
  .ui.two.item.menu
2
2
  = link_to DocContract::ContractTemplate.model_name.human_plural, [DocContract::ContractTemplate], class: ['item', active_class('doc_contract/contract_templates')]
3
3
  = link_to DocContract::ContractInstance.model_name.human_plural, [DocContract::ContractInstance], class: ['item', active_class('doc_contract/contract_instances')]
4
- - if Rails.application.config.doc_contract.show_readme_on_main_page
4
+ - if Rails.application.config.x.doc_contract.show_readme_on_main_page
5
5
  hr
6
6
  #readme_container== readme_html
@@ -4,7 +4,10 @@
4
4
  tbody
5
5
  tr
6
6
  td= at :name
7
- td: .ui.input= f.text_field :name
7
+ td
8
+ .ui.input.error= f.text_field :name
9
+ - if @record.errors[:name].present?
10
+ .ui.left.pointing.red.basic.label= @record.errors[:name].to_sentence
8
11
  tr
9
12
  td
10
13
  = DocContract::ContractTemplate.model_name.human
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ ### NOTE:
4
+ # This is a dummy file to let the vim-rails vim plugin work with the rails engine
@@ -1,16 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  class Name
5
+
3
6
  def human_plural
4
7
  # Try to find the plural name of a model. If none can be found try to find a non namespaced version and return that one
5
- default = Proc.new do |path|
6
- if path.present? and path['/'] # non namespaced model a/b/c => a
7
- unnamespaced_path = path.sub(/\.(\w+)\/[\w\\]+/, '.\1')
8
- I18n.t(unnamespaced_path, default: Proc.new{ human.pluralize })
8
+ default = proc do |path|
9
+ if path.present? and path['/'] # non namespaced model a.b.c/d/e => a.b.c
10
+ unnamespaced_path = path.sub(%r{\.(\w+)/[\w\\]+}, '.\1')
11
+ I18n.t(unnamespaced_path, default: proc{ human.pluralize })
9
12
  else
10
13
  human.pluralize
11
14
  end
12
15
  end
13
- I18n.t("#{@klass.i18n_scope}.models.plural.#{i18n_key}", default: default )
16
+ I18n.t("#{@klass.i18n_scope}.models.plural.#{i18n_key}", default: default)
14
17
  end
15
18
  end
16
19
  end
data/config/routes.rb CHANGED
@@ -1,16 +1,17 @@
1
+ # frozen_string_literal: true
1
2
  DocContract::Engine.routes.draw do
2
3
  resources :contract_templates do
3
4
  member do
4
5
  post :processed_markdown
5
6
  post :processed_html
6
- get :get_pdf
7
+ get :pdf
7
8
  end
8
9
  end
9
10
  resources :contract_instances do
10
11
  member do
11
12
  post :processed_markdown
12
13
  post :processed_html
13
- get :get_pdf
14
+ get :pdf
14
15
  end
15
16
  end
16
17
  root 'application#main'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class CreateDocContractContractTemplates < ActiveRecord::Migration[7.0]
2
3
  def change
3
4
  create_table :doc_contract_contract_templates do |t|
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class AddMarkdownToDocContractContractTemplates < ActiveRecord::Migration[7.0]
2
3
  def change
3
4
  add_column :doc_contract_contract_templates, :markdown, :text
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class AddConfigYmlToDocContractContractTemplates < ActiveRecord::Migration[7.0]
2
3
  def change
3
4
  add_column :doc_contract_contract_templates, :config_yml, :text
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class CreateDocContractContractInstances < ActiveRecord::Migration[7.0]
2
3
  def change
3
4
  create_table :doc_contract_contract_instances do |t|
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class AddTitlepageBackgroundToContractTemplates < ActiveRecord::Migration[7.0]
2
3
  def change
3
4
  add_column :doc_contract_contract_templates, :titlepage_background, :string
@@ -1,27 +1,42 @@
1
- require 'numbers_and_words'
1
+ # frozen_string_literal: true
2
2
  require 'cancancan'
3
- require 'ransack'
3
+ require 'jquery-rails'
4
4
  require 'kaminari'
5
+ require 'numbers_and_words'
6
+ require 'ransack'
7
+ require 'redcarpet'
8
+
5
9
  module DocContract
6
10
  class Engine < ::Rails::Engine
11
+
7
12
  #isolate_namespace self.name.deconstantize.safe_constantize
8
13
  isolate_namespace DocContract
9
- initializer "doc_contract.assets.precompile" do |main_app|
14
+
15
+ initializer 'doc_contract.assets.precompile' do |main_app|
10
16
  #app.config.assets.precompile << "config/engine_name_manifest.js"
11
- main_app.config.assets.precompile << "doc_contract/application.css"
12
- main_app.config.assets.precompile << "doc_contract/application.js"
13
- main_app.config.doc_contract = ActiveSupport::OrderedOptions.new
14
- main_app.config.doc_contract.show_readme_on_main_page = true
15
- main_app.config.doc_contract.link_home_content = '<i class="arrow left icon"></i> Back'
17
+ main_app.config.assets.precompile << 'doc_contract/application.css'
18
+ main_app.config.assets.precompile << 'doc_contract/application.js'
19
+
20
+ # Engine specific config
21
+ # Allow setting false, so check for nil
22
+ main_app.config.x.doc_contract.show_readme_on_main_page = true if main_app.config.x.doc_contract.show_readme_on_main_page.nil?
23
+ main_app.config.x.doc_contract.application_title ||= -> { 'DOC-contract' }
24
+ main_app.config.x.doc_contract.link_home_content ||= -> { '<i class="arrow left icon"></i> Back' }
16
25
  end
17
26
 
18
27
  # add migrations to containing application
19
28
  initializer 'doc_contract.append_migrations' do |app|
20
29
  unless app.root.to_s.match root.to_s
21
- config.paths["db/migrate"].expanded.each do |expanded_path|
22
- app.config.paths["db/migrate"] << expanded_path
30
+ config.paths['db/migrate'].expanded.each do |expanded_path|
31
+ app.config.paths['db/migrate'] << expanded_path
23
32
  end
24
33
  end
25
34
  end
35
+
36
+ initializer 'doc_contract.ensure_set_field_error_proc' do |app|
37
+ app.config.action_view.field_error_proc ||= proc do |html_tag, _instance|
38
+ %|<div class="field_with_errors field error has-error">#{html_tag}</div>|.html_safe
39
+ end
40
+ end
26
41
  end
27
42
  end
@@ -1,25 +1,32 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DocContract
2
4
  class Handlebars
5
+
3
6
  COMPILE_ATTRIBUTES = %w[
4
7
  title subtitle
5
8
  header-left header-center header-right
6
9
  footer-left footer-center footer-right
7
- ]
10
+ ].freeze
11
+
8
12
  class DummyEscaper
13
+
9
14
  def self.escape(value)
10
15
  value
11
16
  end
12
17
  end
13
18
 
19
+ # rubocop:disable Metrics/MethodLength
14
20
  def self.renderer
15
- return @@handlebars_renderer if class_variable_defined? :@@handlebars_renderer
21
+ return @handlebars_renderer if @handlebars_renderer
22
+
16
23
  renderer = ::Handlebars::Handlebars.new
17
24
  renderer.set_escaper DummyEscaper # Do not escape HTML
18
- currency_helper = Proc.new do |context, value, currency_symbol|
19
- if Integer === value or value.to_i == value
20
- sprintf("#{currency_symbol} %.0f,-", value) #.gsub(/(\d)(?=\d{3}+,)/, '\1.')
25
+ currency_helper = proc do |_context, value, currency_symbol|
26
+ if value.is_a?(Integer) or value.to_i == value
27
+ format("#{currency_symbol} %.0f,-", value) #.gsub(/(\d)(?=\d{3}+,)/, '\1.')
21
28
  else
22
- sprintf("#{currency_symbol} %.2f", value.to_f) #.gsub(/(\d)(?=\d{3}+,)/, '\1.')
29
+ format("#{currency_symbol} %.2f", value.to_f) #.gsub(/(\d)(?=\d{3}+,)/, '\1.')
23
30
  end
24
31
  end
25
32
  #renderer.register_helper(:euro) do |context, value|
@@ -29,15 +36,15 @@ module DocContract
29
36
  # sprintf("&euro; %.2f", value.to_f) #.gsub(/(\d)(?=\d{3}+,)/, '\1.')
30
37
  # end
31
38
  #end
32
- eval_boolean = Proc.new do |context, values, compare_lambda|
33
- blocks, comparables = values.partition{|v| v.is_a? ::Handlebars::Tree::Block}
39
+ eval_boolean = proc do |context, values, compare_lambda|
40
+ blocks, comparables = values.partition{ |v| v.is_a? ::Handlebars::Tree::Block }
34
41
  true_blk, false_blk = blocks
35
- comparables = comparables.map{|v| v.is_a?(Parslet::Slice) ? v.to_s : v}
36
- if compare_lambda.arity == 1
37
- are_equal = compare_lambda.call(comparables)
38
- else
39
- are_equal = compare_lambda.call(*comparables)
40
- end
42
+ comparables = comparables.map{ |v| v.is_a?(Parslet::Slice) ? v.to_s : v }
43
+ are_equal = if compare_lambda.arity == 1
44
+ compare_lambda.call(comparables)
45
+ else
46
+ compare_lambda.call(*comparables)
47
+ end
41
48
  if true_blk.items.present? # assumed internal helper usecase without blocks
42
49
  are_equal ? true_blk.fn(context) : false_blk.try(:fn, context)
43
50
  else
@@ -47,31 +54,38 @@ module DocContract
47
54
  renderer.register_helper(:euro) { |context, value| currency_helper.call context, value, '&euro;' }
48
55
  renderer.register_helper(:dollar) { |context, value| currency_helper.call context, value, '$' }
49
56
  renderer.register_helper(:peso) { |context, value| currency_helper.call context, value, '$' }
50
- renderer.register_helper(:plus) {|context, value, addition, *rest| value.to_f + addition.to_f }
51
- renderer.register_helper(:sum) {|context, *values, bkl| (values.first.is_a?(Array) ? values.first : values).map(&:to_f).sum }
52
- renderer.register_helper(:eq) { |context, *values| eval_boolean.call context, values, ->(vals){ vals.uniq.length <= 1 } }
57
+ renderer.register_helper(:plus) { |_context, value, addition, *_rest| value.to_f + addition.to_f }
58
+ renderer.register_helper(:sum) { |_context, *values, _bkl| (values.first.is_a?(Array) ? values.first : values).map(&:to_f).sum }
59
+ renderer.register_helper(:eq) { |context, *values| eval_boolean.call context, values, ->(vals){ vals.uniq.length <= 1 } }
53
60
  renderer.register_helper(:neq) { |context, *values| eval_boolean.call context, values, ->(vals){ vals.uniq.length > 1 } }
54
- renderer.register_helper(:gt) { |context, *values| eval_boolean.call context, values, ->(a, b){ a > b } }
55
- renderer.register_helper(:includes) { |context, *values| eval_boolean.call context, values, ->(vals){ vals.first.include? vals.last } }
56
- renderer.register_helper(:map) do |context, array, key|
61
+ renderer.register_helper(:gt) { |context, *values| eval_boolean.call context, values, ->(a, b){ a > b } }
62
+ renderer.register_helper(:includes) { |context, *values| eval_boolean.call context, values, ->(vals){ vals.first.include? vals.last } }
63
+ renderer.register_helper(:map) do |_context, array, key|
57
64
  return [] unless array.present?
58
- array.map{|e| e[key.to_s] || e[key.to_sym]}
65
+
66
+ array.map{ |e| e[key.to_s] || e[key.to_sym] }
59
67
  end
60
- renderer.register_helper(:upcase) {|context, value| value.to_s.upcase }
61
- renderer.register_helper(:downcase) {|context, value| value.to_s.downcase }
62
- renderer.register_helper(:to_sentence) do |context, array, nester|
68
+ renderer.register_helper(:upcase) { |_context, value| value.to_s.upcase }
69
+ renderer.register_helper(:downcase) { |_context, value| value.to_s.downcase }
70
+ renderer.register_helper(:to_sentence) do |_context, array, nester|
63
71
  case nester
64
72
  when String, Parslet::Slice
65
- array.map{|e| e[nester.to_s] || e[nester.to_sym]}.to_sentence
73
+ array.map{ |e| e[nester.to_s] || e[nester.to_sym] }.to_sentence
66
74
  else
67
75
  array.to_sentence
68
76
  end
69
77
  end
70
- renderer.register_helper(:to_words) { |context, value| value.to_words }
71
- @@handlebars_renderer = renderer
78
+ renderer.register_helper(:to_words) { |_context, value| value.to_words }
79
+ renderer.register_helper(:first_present) do |_context, *args|
80
+ args.find(&:present?)
81
+ end
82
+ @handlebars_renderer = renderer
72
83
  end
84
+ # rubocop:enable Metrics/MethodLength
73
85
 
74
86
  def self.compile(text, object, process_attributes: true)
87
+ return '' unless text.present?
88
+
75
89
  object ||= {}
76
90
  if process_attributes
77
91
  object.stringify_keys!
@@ -83,13 +97,14 @@ module DocContract
83
97
 
84
98
  def self.enrich_object(object)
85
99
  object['today'] = Date.today.iso8601 if object['today'].blank?
86
- object.keys.each do |k|
100
+ iteration_keys = object.keys
101
+ iteration_keys.each do |k|
87
102
  if k =~ /_items$/ and object[k].is_a?(Array)
88
- amounts_sum = object[k].map{|o| (o[:amount] || o['amount']).to_f}.sum
103
+ amounts_sum = object[k].map{ |o| (o[:amount] || o['amount']).to_f }.sum
89
104
  object["#{k}_total"] = amounts_sum
90
105
  end
91
106
  if COMPILE_ATTRIBUTES.include? k
92
- #TODO check self reference, maybe even circular?
107
+ #TODO: check self reference, maybe even circular?
93
108
  object[k] = compile(object[k], object, process_attributes: false)
94
109
  end
95
110
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DocContract
2
- VERSION = "0.1.6"
4
+ VERSION = '0.2.0'
3
5
  end
data/lib/doc_contract.rb CHANGED
@@ -1,6 +1,7 @@
1
- require "doc_contract/version"
2
- require "doc_contract/engine"
3
- require "doc_contract/handlebars"
1
+ # frozen_string_literal: true
2
+ require 'doc_contract/version'
3
+ require 'doc_contract/engine'
4
+ require 'doc_contract/handlebars'
4
5
  require 'ruby-handlebars'
5
6
  require 'open3'
6
7
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # desc "Explaining what the task does"
2
3
  # task :doc_contract do
3
4
  # # Task goes here
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doc_contract
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin ter Kuile
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-17 00:00:00.000000000 Z
11
+ date: 2023-08-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: cancancan
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: ruby-handlebars
28
+ name: jquery-rails
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: redcarpet
42
+ name: kaminari
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: cancancan
56
+ name: numbers_and_words
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: ransack
70
+ name: rails
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: kaminari
84
+ name: ransack
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: numbers_and_words
98
+ name: redcarpet
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -109,13 +109,13 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: rspec-rails
112
+ name: ruby-handlebars
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
116
116
  - !ruby/object:Gem::Version
117
117
  version: '0'
118
- type: :development
118
+ type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
@@ -123,7 +123,7 @@ dependencies:
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: factory_bot_rails
126
+ name: coffee-rails
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - ">="
@@ -137,7 +137,7 @@ dependencies:
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
- name: jquery-rails
140
+ name: factory_bot_rails
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - ">="
@@ -151,7 +151,7 @@ dependencies:
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
153
  - !ruby/object:Gem::Dependency
154
- name: coffee-rails
154
+ name: rspec-rails
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - ">="
@@ -187,6 +187,7 @@ files:
187
187
  - app/controllers/doc_contract/contract_templates_controller.rb
188
188
  - app/helpers/doc_contract/application_helper.rb
189
189
  - app/models/concerns/yaml_validator.rb
190
+ - app/models/doc_contract/application_record.rb
190
191
  - app/models/doc_contract/contract_instance.rb
191
192
  - app/models/doc_contract/contract_template.rb
192
193
  - app/views/doc_contract/application/_button-destroy-record.html.slim
@@ -217,6 +218,7 @@ files:
217
218
  - app/views/doc_contract/kaminari/_paginator.html.slim
218
219
  - app/views/doc_contract/kaminari/_prev_page.html.slim
219
220
  - app/views/layouts/doc_contract/application.html.slim
221
+ - config/environment.rb
220
222
  - config/initializers/human_plural.rb
221
223
  - config/locales/en.yml
222
224
  - config/routes.rb
@@ -262,7 +264,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
262
264
  - !ruby/object:Gem::Version
263
265
  version: '0'
264
266
  requirements: []
265
- rubygems_version: 3.3.7
267
+ rubygems_version: 3.4.10
266
268
  signing_key:
267
269
  specification_version: 4
268
270
  summary: Create nice and easy contracts based on pandoc