markdown_record 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +63 -43
  3. data/app/helpers/markdown_record/application_helper.rb +23 -0
  4. data/app/helpers/markdown_record/controller_helpers.rb +1 -1
  5. data/app/helpers/markdown_record/view_helpers.rb +9 -3
  6. data/{lib → app/models}/markdown_record/base.rb +10 -0
  7. data/{lib → app/models}/markdown_record/content_fragment.rb +17 -2
  8. data/lib/generators/markdown_record_generator.rb +6 -0
  9. data/lib/markdown_record/configuration.rb +4 -0
  10. data/lib/markdown_record/file_sorting/base.rb +25 -0
  11. data/lib/markdown_record/file_sorting/date_sorter.rb +14 -0
  12. data/lib/markdown_record/file_sorting/sem_ver_sorter.rb +47 -0
  13. data/lib/markdown_record/{association.rb → models/association.rb} +20 -3
  14. data/lib/markdown_record/{associations.rb → models/associations.rb} +17 -9
  15. data/lib/markdown_record/{content_associations.rb → models/content_associations.rb} +4 -2
  16. data/lib/markdown_record/models/filtering.rb +13 -0
  17. data/lib/markdown_record/models/filters/array_filter.rb +11 -0
  18. data/lib/markdown_record/models/filters/base_filter.rb +35 -0
  19. data/lib/markdown_record/models/filters/hash_filter.rb +81 -0
  20. data/lib/markdown_record/models/filters/nil_filter.rb +11 -0
  21. data/lib/markdown_record/models/filters/range_filter.rb +11 -0
  22. data/lib/markdown_record/models/filters/regexp_filter.rb +11 -0
  23. data/lib/markdown_record/models/filters/symbol_filter.rb +14 -0
  24. data/lib/markdown_record/models/filters.rb +22 -0
  25. data/lib/markdown_record/models/model_inflator.rb +65 -0
  26. data/lib/markdown_record/path_utilities.rb +20 -11
  27. data/lib/markdown_record/rendering/content_dsl/attribute.rb +22 -0
  28. data/lib/markdown_record/{content_dsl → rendering/content_dsl}/directory_fragment.rb +3 -3
  29. data/lib/markdown_record/{content_dsl → rendering/content_dsl}/disable.rb +2 -2
  30. data/lib/markdown_record/{content_dsl → rendering/content_dsl}/enable.rb +2 -2
  31. data/lib/markdown_record/{content_dsl → rendering/content_dsl}/end_attribute.rb +3 -3
  32. data/lib/markdown_record/{content_dsl → rendering/content_dsl}/end_model.rb +3 -3
  33. data/lib/markdown_record/{content_dsl → rendering/content_dsl}/fragment.rb +3 -3
  34. data/lib/markdown_record/rendering/content_dsl/model.rb +22 -0
  35. data/lib/markdown_record/rendering/content_dsl/scope.rb +22 -0
  36. data/lib/markdown_record/{content_dsl → rendering/content_dsl}/use_layout.rb +3 -3
  37. data/lib/markdown_record/rendering/content_dsl.rb +45 -0
  38. data/lib/markdown_record/rendering/html_renderer.rb +22 -0
  39. data/lib/markdown_record/{indexer.rb → rendering/indexer.rb} +0 -10
  40. data/lib/markdown_record/rendering/json_renderer.rb +20 -0
  41. data/lib/markdown_record/rendering/nodes/html_base.rb +95 -0
  42. data/lib/markdown_record/rendering/nodes/html_directory.rb +51 -0
  43. data/lib/markdown_record/rendering/nodes/html_file.rb +48 -0
  44. data/lib/markdown_record/rendering/nodes/json_base.rb +55 -0
  45. data/lib/markdown_record/rendering/nodes/json_directory.rb +69 -0
  46. data/lib/markdown_record/rendering/nodes/json_file.rb +172 -0
  47. data/lib/markdown_record/{rendering.rb → rendering/rendering.rb} +1 -1
  48. data/lib/markdown_record/{validator.rb → rendering/validator.rb} +4 -4
  49. data/lib/markdown_record/version.rb +1 -1
  50. data/lib/markdown_record.rb +21 -14
  51. data/templates/demo/content/10_custom_models_and_associations.md.erb +27 -7
  52. data/templates/demo/content/11_controller_helpers.md.erb +2 -2
  53. data/templates/demo/content/12_configuration.md.erb +22 -3
  54. data/templates/demo/content/13_sandbox/1_foo.md +2 -1
  55. data/templates/demo/content/13_sandbox/2_sandbox_nested/1_bar.md +4 -1
  56. data/templates/demo/content/1_home.md.erb +30 -13
  57. data/templates/demo/content/2_installation.md.erb +61 -46
  58. data/templates/demo/content/3_rendering_basics.md.erb +3 -3
  59. data/templates/demo/content/4_content_dsl.md.erb +22 -11
  60. data/templates/demo/content/5_routes.md.erb +10 -7
  61. data/templates/demo/content/6_model_basics.md.erb +11 -11
  62. data/templates/demo/content/7_content_frags.md.erb +9 -6
  63. data/templates/demo/content/8_erb_syntax_and_view_helpers.md.erb +32 -11
  64. data/templates/demo/content/9_layouts.md.erb +3 -3
  65. data/templates/demo/layouts/_global_layout.html.erb +1 -0
  66. data/templates/demo/models/dsl_command.rb +6 -0
  67. data/templates/demo/models/section.rb +5 -0
  68. data/templates/render_content.thor +2 -1
  69. data/templates/tests/assets/images/ruby-logo.png +0 -0
  70. data/templates/tests/content/1_test_files_home.md.erb +31 -0
  71. data/templates/tests/content/2_content_dsl_tests/1_content_dsl.md.erb +162 -0
  72. data/templates/tests/content/2_content_dsl_tests/2_nested_directory/1_associations.md.erb +83 -0
  73. data/templates/tests/layouts/_concatenated_layout.html.erb +12 -0
  74. data/templates/tests/layouts/_custom_layout.html.erb +14 -0
  75. data/templates/tests/layouts/_file_layout.html.erb +15 -0
  76. data/templates/tests/layouts/_global_layout.html.erb +116 -0
  77. metadata +53 -34
  78. data/app/models/markdown_record/demo/dsl_command.rb +0 -10
  79. data/app/models/markdown_record/demo/section.rb +0 -9
  80. data/app/models/markdown_record/tests/child_model.rb +0 -15
  81. data/app/models/markdown_record/tests/fake_active_record_model.rb +0 -13
  82. data/app/models/markdown_record/tests/model.rb +0 -15
  83. data/app/models/markdown_record/tests/other_child_model.rb +0 -15
  84. data/lib/markdown_record/cli.rb +0 -54
  85. data/lib/markdown_record/content_dsl/attribute.rb +0 -22
  86. data/lib/markdown_record/content_dsl/model.rb +0 -23
  87. data/lib/markdown_record/content_dsl/render_format.rb +0 -22
  88. data/lib/markdown_record/content_dsl/render_strategy.rb +0 -22
  89. data/lib/markdown_record/content_dsl.rb +0 -37
  90. data/lib/markdown_record/html_renderer.rb +0 -194
  91. data/lib/markdown_record/json_renderer.rb +0 -270
  92. data/lib/markdown_record/model_inflator.rb +0 -107
  93. data/lib/markdown_record/routes_renderer.rb +0 -0
  94. /data/lib/markdown_record/{file_saver.rb → rendering/file_saver.rb} +0 -0
@@ -1,15 +0,0 @@
1
- module MarkdownRecord
2
- module Tests
3
- class OtherChildModel < ::MarkdownRecord::Base
4
- attribute :string_field
5
- attribute :int_field
6
- attribute :float_field
7
- attribute :bool_field
8
- attribute :date_field
9
- attribute :maybe_field
10
- attribute :hash_field
11
-
12
- belongs_to_content :model
13
- end
14
- end
15
- end
@@ -1,54 +0,0 @@
1
- require 'thor'
2
-
3
- module MarkdownRecord
4
-
5
- class Cli < Thor
6
- include ::Thor::Actions
7
-
8
- source_root File.expand_path("../../spec/dummy", __dir__)
9
-
10
- desc "install", "installs rendered comparison files for specs"
11
- def install
12
- # Install the gem in the dummy app
13
- system "cd spec/dummy && rails g markdown_record"
14
-
15
- # Run render_content thor task to generate content and save it
16
- system "cd spec/dummy && thor render_content:all -s"
17
-
18
- # Copy the generated content to the spec folder for the specs to use
19
- copy_file "markdown_record/rendered/content/part_1/chapter_1/content.html", "spec/rendered/chapter_1/content.html"
20
- copy_file "markdown_record/rendered/content/part_1/chapter_1/content.json", "spec/rendered/chapter_1/content.json"
21
- copy_file "markdown_record/rendered/content/part_1/chapter_1/content_fragments.json", "spec/rendered/chapter_1/content_fragments.json"
22
-
23
- copy_file "markdown_record/rendered/content/part_1/chapter_2/content.html", "spec/rendered/chapter_2/content.html"
24
- copy_file "markdown_record/rendered/content/part_1/chapter_2/content.json", "spec/rendered/chapter_2/content.json"
25
- copy_file "markdown_record/rendered/content/part_1/chapter_2/content_fragments.json", "spec/rendered/chapter_2/content_fragments.json"
26
-
27
- copy_file "markdown_record/rendered/content.html", "spec/rendered/concatenated/content.html"
28
- copy_file "markdown_record/rendered/content.json", "spec/rendered/concatenated/content.json"
29
- copy_file "markdown_record/rendered/content_fragments.json", "spec/rendered/concatenated/content_fragments.json"
30
-
31
- # Run render content again with a custom layout
32
- system "cd spec/dummy && thor render_content:all -s -l \"_custom_layout.html.erb\" -r full"
33
-
34
- # Copy the new files to the spec directory
35
- copy_file "markdown_record/rendered/content.html", "spec/rendered/custom_layout/content.html"
36
- copy_file "markdown_record/rendered/content/part_1/chapter_1/content.html", "spec/rendered/custom_layout/chapter_1/content.html"
37
-
38
- # Run render content again with a custom layout
39
- system "cd spec/dummy && thor render_file:json -s -f part_1/chapter_1/content.md"
40
- copy_file "markdown_record/rendered/content/part_1/chapter_1/content.json", "spec/rendered/chapter_1/no_frag_content.json"
41
-
42
- # Remove generated content and installed files
43
- FileUtils.remove_dir("spec/dummy/markdown_record/rendered", true)
44
- FileUtils.remove_dir("spec/dummy/markdown_record/content", true)
45
- FileUtils.remove_entry("spec/dummy/markdown_record/layouts/_concatenated_layout.html.erb", true)
46
- FileUtils.remove_entry("spec/dummy/markdown_record/layouts/_file_layout.html.erb", true)
47
- FileUtils.remove_entry("spec/dummy/lib/tasks/render_content.thor", true)
48
- FileUtils.remove_entry("spec/dummy/lib/tasks/render_file.thor", true)
49
- FileUtils.remove_entry("spec/dummy/config/initializers/markdown_record.rb", true)
50
- FileUtils.remove_entry("spec/dummy/Thorfile", true)
51
- gsub_file "spec/dummy/config/routes.rb", "\n mount MarkdownRecord::Engine, at: MarkdownRecord.config.mount_path, as: \"markdown_record\"", ""
52
- end
53
- end
54
- end
@@ -1,22 +0,0 @@
1
- module MarkdownRecord
2
- module ContentDsl
3
- module Attribute
4
- REGEX = /(?<!`|`\\n|`html\\n)<!--\s*attribute\s*:\s*(\w+)\s*(?::((?:html|md|int|float|string)?))?-->(?!`|\\n`)/
5
- ENCODED_REGEX = /(?<!<code>|<code class="html">)&lt;!--\s*attribute\s*:\s*(\w+)\s*(?::((?:html|md|int|float|string)?))?--&gt;(?!<\/code>)/
6
-
7
- def attribute_dsl(text)
8
- match = text.match(REGEX)
9
-
10
- if match
11
- [match[1].strip, match[2]&.strip]
12
- else
13
- nil
14
- end
15
- end
16
-
17
- def self.remove_dsl(text)
18
- text.gsub(ENCODED_REGEX, "")
19
- end
20
- end
21
- end
22
- end
@@ -1,23 +0,0 @@
1
- module MarkdownRecord
2
- module ContentDsl
3
- module Model
4
- TEMP = /<!--\s*model\s*({[\s"'\\\w:,.\[\]\{\}_\/]*})\s*-->/
5
- REGEX = /(?<!`|`\\n|`html\\n)<!--\s*model\s*({[\s"'\\\w:,.\[\]\{\}_\/]*})\s*-->(?!`|\\n`)/
6
- ENCODED_REGEX = /(?<!<code>|<code class="html">)&lt;!--\s*model\s*({[\s"'\\\w:,.\[\]\{\}_\/]*})\s*--&gt;(?!<\/code>)/
7
-
8
- def model_dsl(text)
9
- match = text.match(REGEX)
10
-
11
- if match
12
- JSON.parse(match[1])
13
- else
14
- nil
15
- end
16
- end
17
-
18
- def self.remove_dsl(text)
19
- text.gsub(ENCODED_REGEX, "")
20
- end
21
- end
22
- end
23
- end
@@ -1,22 +0,0 @@
1
- module MarkdownRecord
2
- module ContentDsl
3
- module RenderFormat
4
- REGEX = /(?<!`|`\\n|`html\\n)<!--\s*render_format\s*:\s*(.*)\s*-->(?!`|\\n`)/
5
- ENCODED_REGEX = /(?<!<code>|<code class="html">)&lt;!--\s*render_format\s*:\s*(.*)\s*--&gt;(?!<\/code>)/
6
-
7
- def render_format_dsl(text)
8
- match = text.match(REGEX)
9
-
10
- if match
11
- match[1].strip
12
- else
13
- nil
14
- end
15
- end
16
-
17
- def self.remove_dsl(text)
18
- text.gsub(ENCODED_REGEX, "")
19
- end
20
- end
21
- end
22
- end
@@ -1,22 +0,0 @@
1
- module MarkdownRecord
2
- module ContentDsl
3
- module RenderStrategy
4
- REGEX = /(?<!`|`\\n|`html\\n)<!--\s*render_strategy\s*:\s*(.*)\s*-->(?!`|\\n`)/
5
- ENCODED_REGEX = /(?<!<code>|<code class="html">)&lt;!--\s*render_strategy\s*:\s*(.*)\s*--&gt;(?!<\/code>)/
6
-
7
- def render_strategy_dsl(text)
8
- match = text.match(REGEX)
9
-
10
- if match
11
- match[1].strip
12
- else
13
- nil
14
- end
15
- end
16
-
17
- def self.remove_dsl(text)
18
- text.gsub(ENCODED_REGEX, "")
19
- end
20
- end
21
- end
22
- end
@@ -1,37 +0,0 @@
1
- require "markdown_record/content_dsl/model"
2
- require "markdown_record/content_dsl/attribute"
3
- require "markdown_record/content_dsl/end_attribute"
4
- require "markdown_record/content_dsl/end_model"
5
- require "markdown_record/content_dsl/fragment"
6
- require "markdown_record/content_dsl/directory_fragment"
7
- require "markdown_record/content_dsl/use_layout"
8
- require "markdown_record/content_dsl/disable"
9
- require "markdown_record/content_dsl/enable"
10
-
11
- module MarkdownRecord
12
- module ContentDsl
13
- include Model
14
- include Attribute
15
- include EndAttribute
16
- include EndModel
17
- include DirectoryFragment
18
- include Fragment
19
- include UseLayout
20
- include Disable
21
- include Enable
22
-
23
- HTML_COMMENT_REGEX = /(<!--(?:(?:\s|.)(?!-->))*(?:.|\s)-->)/
24
-
25
- def remove_dsl(text)
26
- text = Model.remove_dsl(text)
27
- text = Attribute.remove_dsl(text)
28
- text = EndAttribute.remove_dsl(text)
29
- text = EndModel.remove_dsl(text)
30
- text = Fragment.remove_dsl(text)
31
- text = UseLayout.remove_dsl(text)
32
- text = Disable.remove_dsl(text)
33
- text = Enable.remove_dsl(text)
34
- text
35
- end
36
- end
37
- end
@@ -1,194 +0,0 @@
1
- require "redcarpet"
2
- require "htmlbeautifier"
3
-
4
- module MarkdownRecord
5
- class HtmlRenderer < ::Redcarpet::Render::HTML
6
- include ::MarkdownRecord::PathUtilities
7
- include ::MarkdownRecord::ContentDsl
8
-
9
- HTML_SUBSTITUTIONS = {
10
- /<!---/ => "<!--",
11
- /&lt;!---/ => "&lt;!--"
12
- }
13
-
14
- def initialize(
15
- file_saver: ::MarkdownRecord::FileSaver.new)
16
- super(::MarkdownRecord.config.html_render_options)
17
- @indexer = ::MarkdownRecord::Indexer.new
18
- @markdown = ::Redcarpet::Markdown.new(self, ::MarkdownRecord.config.markdown_extensions)
19
- @file_saver = file_saver
20
- end
21
-
22
- def render_html_for_subdirectory(subdirectory: "", **options)
23
- content = @indexer.index(subdirectory: subdirectory)
24
- rendered_subdirectory = base_content_path.join(subdirectory)
25
-
26
- html_content = render_html_recursively(content, rendered_subdirectory.to_s)
27
- processed_html = process_html_recursively(html_content[rendered_subdirectory.to_s], rendered_subdirectory, options)
28
- final_html = finalize_html_recursively(processed_html, rendered_subdirectory)
29
-
30
- save_content_recursively(final_html, options, rendered_subdirectory)
31
- { :html_content => processed_html, :saved_files => @file_saver.saved_files }
32
- nil
33
- end
34
-
35
- private
36
-
37
- def render_html_recursively(file_or_directory, file_or_directory_name)
38
- case file_or_directory.class.name
39
- when Hash.name # if it is a directory
40
- directory_hash = { file_or_directory_name => {} } # hash representing the directory and its contents
41
-
42
- file_or_directory.each do |child_file_or_directory_name, child_file_or_directory|
43
- child_content_hash = render_html_recursively(child_file_or_directory, child_file_or_directory_name)
44
- directory_hash[file_or_directory_name].merge!(child_content_hash)
45
- end
46
-
47
- directory_hash
48
- when String.name # if it is a file
49
- { file_or_directory_name => render_html(file_or_directory) }
50
- end
51
- end
52
-
53
- def render_html(html)
54
- rendered_html = @markdown.render(html)
55
- remove_dsl(rendered_html)
56
- end
57
-
58
- def process_html_recursively(file_or_directory, full_path, options)
59
- case file_or_directory.class.name
60
- when Hash.name
61
- directory_hash = { full_path.to_s => {} } # hash representing the directory and its contents
62
-
63
- file_or_directory.each do |child_file_or_directory_name, child_file_or_directory|
64
- child_content_hash = process_html_recursively(child_file_or_directory, full_path.join(child_file_or_directory_name), options)
65
- directory_hash[full_path.to_s].merge!(child_content_hash)
66
- end
67
-
68
- if options[:concat]
69
- concatenated_html = concatenate_html_recursively(directory_hash[full_path.to_s], []).join("\r\n")
70
- directory_hash["#{full_path.to_s}.concat"] = process_html(concatenated_html, full_path.to_s, concatenated_layout)
71
- end
72
-
73
- directory_hash.compact
74
- when String.name # if it is a file
75
- if options[:deep]
76
- { full_path.to_s => process_html(file_or_directory, full_path, custom_layout(file_or_directory) || file_layout) }
77
- else
78
- { }
79
- end
80
- end
81
- end
82
-
83
- def process_html(html, full_path, layout = nil)
84
- processed_html = html.gsub(/<p>(\&lt;%(\S|\s)*?%\&gt;)<\/p>/){ CGI.unescapeHTML($1) }
85
- processed_html = processed_html.gsub(/(\&lt;%(\S|\s)*?%\&gt;)/){ CGI.unescapeHTML($1) }
86
- locals = erb_locals_from_path(full_path.to_s)
87
- processed_html = render_erb(processed_html, locals) if full_path.to_s.ends_with?(".md.erb")
88
- processed_html = render_erb(layout, locals.merge(html: processed_html)) if layout
89
- processed_html
90
- end
91
-
92
- def render_erb(html, locals)
93
- render_controller = ::MarkdownRecord.config.render_controller || ::ApplicationController
94
- rendered_html = render_controller.render(
95
- inline: html,
96
- locals: locals
97
- ).to_str
98
- rendered_html
99
- end
100
-
101
- def concatenate_html_recursively(content, html)
102
- case content.class.name
103
- when Hash.name
104
- sorted_hash_values(content).each do |v|
105
- concatenate_html_recursively(v, html)
106
- end
107
- when String.name
108
- html << content
109
- end
110
- html
111
- end
112
-
113
- def sorted_hash_values(hash)
114
- values = []
115
- keys = hash.keys.sort_by do |k|
116
- basename = k.split("/").last
117
- m = basename.match(/^(\d+)_/)
118
- m.try(:[], 1).to_i || k
119
- end
120
-
121
- keys.each do |k|
122
- values << hash[k] if !k.include?(".concat")
123
- end
124
- values
125
- end
126
-
127
- def custom_layout(html)
128
- layout = use_layout_dsl(html)
129
- return unless layout
130
-
131
- File.read(::MarkdownRecord.config.layout_directory.join(layout))
132
- end
133
-
134
- def global_layout
135
- global_layout_path = ::MarkdownRecord.config.global_layout_path
136
- @global_layout ||= global_layout_path ? layout(global_layout_path) : nil
137
- end
138
-
139
- def concatenated_layout
140
- concatenated_layout_path = ::MarkdownRecord.config.concatenated_layout_path
141
- @concatenated_layout ||= concatenated_layout_path ? layout(concatenated_layout_path) : nil
142
- end
143
-
144
- def file_layout
145
- file_layout_path = ::MarkdownRecord.config.file_layout_path
146
- @file_layout ||= file_layout_path ? layout(file_layout_path) : nil
147
- end
148
-
149
- def layout(path)
150
- File.read(::MarkdownRecord.config.layout_directory.join(path))
151
- end
152
-
153
- def finalize_html_recursively(content, rendered_subdirectory)
154
- case content.class.name
155
- when Hash.name
156
- final_hash = {}
157
- content.each do |key, value|
158
- child_path = rendered_subdirectory.join(key)
159
- final_hash[key] = finalize_html_recursively(value, child_path)
160
- end
161
- final_hash
162
- when String.name
163
- finalize_html(content, rendered_subdirectory)
164
- end
165
- end
166
-
167
- def finalize_html(html, full_path)
168
- locals = erb_locals_from_path(full_path)
169
- final_html = html
170
- final_html = render_erb(global_layout, locals.merge(html: final_html)) if global_layout
171
-
172
- HTML_SUBSTITUTIONS.each do |find, replace|
173
- final_html = final_html.gsub(find, replace)
174
- end
175
-
176
- final_html = final_html.squeeze("\n")
177
- final_html = HtmlBeautifier.beautify(final_html)
178
- final_html
179
- end
180
-
181
- def save_content_recursively(content, options, rendered_subdirectory)
182
- case content.class.name
183
- when Hash.name
184
- content.each do |key, value|
185
- child_path = rendered_subdirectory.join(key)
186
- save_content_recursively(value, options, child_path)
187
- end
188
- when String.name
189
- path = clean_path(rendered_subdirectory.to_s)
190
- @file_saver.save_to_file(content, "#{path}.html", options)
191
- end
192
- end
193
- end
194
- end
@@ -1,270 +0,0 @@
1
- require "redcarpet"
2
- require "redcarpet/render_strip"
3
-
4
- module MarkdownRecord
5
- class JsonRenderer
6
- include ::MarkdownRecord::PathUtilities
7
- include ::MarkdownRecord::ContentDsl
8
-
9
- def initialize(file_saver: ::MarkdownRecord::FileSaver.new)
10
- @indexer = MarkdownRecord::Indexer.new
11
- @json_models = {}
12
- @described_models = []
13
- @file_saver = file_saver
14
- end
15
-
16
- def render_models_for_subdirectory(subdirectory: "", **options)
17
- @directory_meta = {}
18
- content = @indexer.index(subdirectory: subdirectory)
19
-
20
- rendered_subdirectory = base_content_path.join(subdirectory)
21
- json_hash, _ = render_models_recursively(content, rendered_subdirectory, options)
22
-
23
- save_content_recursively(json_hash, options, Pathname.new(""))
24
- json_hash
25
- end
26
-
27
- def render_models_for_file(file_path:, **options)
28
- file = @indexer.file(file_path)
29
-
30
- # render json models
31
- json = render_models(file, file_path, options)
32
-
33
- # save json
34
- @file_saver.save_to_file(json.to_json, "#{clean_path(file_path)}.json", options)
35
-
36
- json
37
- end
38
-
39
- private
40
-
41
- def render_models_recursively(file_or_directory, full_path, options)
42
- case file_or_directory.class.name;
43
- when Hash.name # if it is a directory
44
- directory_hash, concat_hash = *render_nested_models(file_or_directory, full_path, options)
45
-
46
- # concatenate child hashes if :concat = true
47
- if options[:concat]
48
- concatenate_nested_models(full_path, directory_hash, concat_hash, options)
49
- end
50
-
51
- [directory_hash, concat_hash]
52
- when String.name # if it is a file
53
- content = render_models(file_or_directory, full_path, options)
54
-
55
- if options[:deep] && options[:render_content_fragment_json]
56
- add_content_fragment_for_file(content, full_path, false, @fragment_meta)
57
- end
58
-
59
- content_hash = { full_path.basename.to_s => content }
60
- result = [{}, {}]
61
- result[0] = content_hash if options[:deep]
62
- result[1] = content_hash if options[:concat]
63
- result
64
- end
65
- end
66
-
67
- def render_nested_models(file_or_directory, full_path, options)
68
- directory_hash = { full_path.basename.to_s => {} } # hash representing the directory and its contents
69
- concat_hash = { full_path.basename.to_s => {} }
70
- # iterate through directory contents
71
- file_or_directory.each do |child_file_or_directory_name, child_file_or_directory|
72
-
73
- # get full path for next recursion
74
- child_full_path = full_path.join(child_file_or_directory_name)
75
- # get response from next recursion
76
- child_content_hash, child_concat_hash = render_models_recursively(
77
- child_file_or_directory,
78
- child_full_path,
79
- options
80
- )
81
- # merge response hashes
82
- concat_hash[full_path.basename.to_s].merge!(child_concat_hash)
83
- directory_hash[full_path.basename.to_s].merge!(child_content_hash)
84
- end
85
-
86
- [directory_hash, concat_hash]
87
- end
88
-
89
- def concatenate_nested_models(full_path, directory_hash, concat_hash, options)
90
- concatenated_json = {}
91
- concatenate_json_recursively(concat_hash, concatenated_json)
92
-
93
- # add content fragments if render_content_fragment_json = true
94
- if options[:render_content_fragment_json]
95
- filename, subdirectory = full_path_to_parts(full_path)
96
- directory_meta = @directory_meta[clean_path("#{subdirectory}/#{filename}")] || {}
97
-
98
- add_content_fragment_for_file(concat_hash[full_path.basename.to_s], full_path, true, directory_meta)
99
- add_content_fragment_for_file(concatenated_json, full_path, true, directory_meta)
100
- end
101
-
102
- directory_hash["#{full_path.basename.to_s}.concat"] = concatenated_json
103
- end
104
-
105
- def render_models(content, full_path, options)
106
-
107
- filename, subdirectory = full_path_to_parts(full_path)
108
-
109
- @described_models = []
110
- @json_models = {}
111
- @fragment_meta = {}
112
- enabled = true
113
-
114
- content.split(HTML_COMMENT_REGEX).each do |text|
115
- dsl_command = HTML_COMMENT_REGEX =~ text
116
-
117
- if dsl_command
118
- enabled = false if disable_dsl(text)
119
- enabled = true if enable_dsl(text)
120
- end
121
-
122
- if dsl_command && enabled
123
- extract_model(text, filename, subdirectory)
124
- extract_fragment_meta(text, subdirectory)
125
- extract_attribute(text)
126
- pop_attribute(text)
127
- pop_model(text)
128
- else
129
- append_to_attribute(text)
130
- end
131
- end
132
-
133
- @described_models.each do |model|
134
- finalize_attribute(model)
135
- end
136
-
137
- @json_models.dup
138
- end
139
-
140
- def add_content_fragment_for_file(json, full_path, concatenated, meta)
141
- content_fragment = fragment_attributes_from_path(full_path).merge("meta" => meta, "concatenated" => concatenated)
142
-
143
- json["markdown_record/content_fragment"] ||= []
144
- json["markdown_record/content_fragment"] << content_fragment
145
- end
146
-
147
- def concatenate_json_recursively(directory_hash, concatenated_json)
148
- directory_hash.each do |key, value|
149
- case value.class.name
150
- when Hash.name
151
- concatenate_json_recursively(value, concatenated_json)
152
- when Array.name
153
- concatenated_json[key] ||= []
154
- concatenated_json[key] += value
155
- end
156
- end
157
- end
158
-
159
- def save_content_recursively(content, options, rendered_subdirectory)
160
- if content&.values&.first.is_a?(Array)
161
- fragments = content.slice("markdown_record/content_fragment")
162
- non_fragments = content.except("markdown_record/content_fragment")
163
- path = clean_path(rendered_subdirectory.to_s)
164
- @file_saver.save_to_file(non_fragments.to_json, "#{path}.json", options)
165
- @file_saver.save_to_file(fragments.to_json, "#{path}.json", options, true)
166
- else
167
- content.each do |key, value|
168
- child_path = rendered_subdirectory.join(key)
169
- save_content_recursively(value, options, child_path)
170
- end
171
- end
172
- end
173
-
174
- def extract_model(html, filename, subdirectory)
175
- model = model_dsl(html)
176
-
177
- if model
178
- return unless model["type"].present?
179
-
180
- model["subdirectory"] = clean_path(subdirectory)
181
- model["filename"] = clean_path(filename)
182
-
183
- # reset "type" to not have a prefix, in order to ensure
184
- # consistent results between the internal only :klass filter
185
- # which is used as an index in a hash (and has the prefix removed
186
- # for consistency and deterministic behavior)
187
- # and the externally filterable :type field.
188
- model["type"] = model["type"].delete_prefix("::").strip
189
-
190
- @json_models[model["type"]] ||= []
191
- @json_models[model["type"]] << model
192
-
193
- @described_models.push(model)
194
- end
195
- end
196
-
197
- def extract_fragment_meta(html, subdirectory)
198
- meta = fragment_dsl(html)
199
-
200
- if meta
201
- @fragment_meta = meta
202
- end
203
-
204
- directory_meta = directory_fragment_dsl(html)
205
-
206
- if directory_meta
207
- @directory_meta[subdirectory] = directory_meta
208
- end
209
- end
210
-
211
- def extract_attribute(text)
212
- attribute, type = attribute_dsl(text)
213
- type ||= "md"
214
-
215
- if @described_models.last && attribute
216
- model = @described_models.last
217
- model[:described_attribute_type] = type
218
- model[:described_attribute] = attribute
219
- model[model[:described_attribute]] = []
220
- end
221
- end
222
-
223
- def append_to_attribute(text)
224
- return if text.match(HTML_COMMENT_REGEX)
225
-
226
- @described_models.each do |model|
227
- next unless model[:described_attribute].present?
228
-
229
- model[model[:described_attribute]] ||= []
230
- model[model[:described_attribute]] << text
231
- end
232
- end
233
-
234
- def pop_attribute(text)
235
- if @described_models.last && end_attribute_dsl(text)
236
- finalize_attribute(@described_models.last)
237
- end
238
- end
239
-
240
- def pop_model(html)
241
- if end_model_dsl(html)
242
- @described_models.pop
243
- end
244
- end
245
-
246
- def finalize_attribute(model)
247
- return if model[:described_attribute].nil?
248
-
249
- attribute_name = model.delete(:described_attribute)
250
- attribute = model[attribute_name].join("\n")
251
- type = model.delete(:described_attribute_type)
252
-
253
- case type
254
- when "html"
255
- renderer = Redcarpet::Render::HTML.new
256
- attribute = Redcarpet::Markdown.new(renderer).render(attribute)
257
- when "md"
258
- attribute = attribute.strip
259
- when "int"
260
- attribute = attribute.strip.gsub("\n", "").to_i
261
- when "float"
262
- attribute = attribute.strip.gsub("\n", "").to_f
263
- when "string"
264
- attribute = Redcarpet::Markdown.new(::Redcarpet::Render::StripDown).render(attribute).strip
265
- end
266
-
267
- model[attribute_name] = attribute
268
- end
269
- end
270
- end