middleman-mdocs 0.1.0.62562 → 0.1.1.75132

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: 8a178d824ca8aa52558c1d79e3caa57d591f7ca6061de94e7aa7bf8beb2deac5
4
- data.tar.gz: 3ae7963d4b26818877c8263dd682d7da4e425cad6eea79d0910c0218b870a8d8
3
+ metadata.gz: af19925233fb69d9d19cfbe262c89297ff40c6a8e39aa1ae539169f51d6bca44
4
+ data.tar.gz: 01afb1fc1310d5d8c079d7867148c6d63379576ed3eda72570204b25ce6125fa
5
5
  SHA512:
6
- metadata.gz: 9e8662688f936f346461d76a3c02e531de5330ac1d99edcfe9cd44a61ce4fdbde488e1c918d00b00c51559f83532cf898af5ce8238761d66412fbc87e3bf8135
7
- data.tar.gz: 151d8aa1ba4f99207382b1e976b1c28daecdf8618d578b6221952802f071b0fae09782a97ffed92d30bb986adef2c3d6488b56c2fc33f44b2b5a2eac451f7202
6
+ metadata.gz: bb2973c1d9f864587bec83396145c3a14b5df05d11b8478b84ec5d5e8d5cedafe0ba2e643cea6286cbf7e4a1a93d4affefa007dba8012bf7e486e2613daf43bd
7
+ data.tar.gz: 05a90cf5c51a1b2f29967755082a80e2b5fe2be299724ce322adb172c97cd070b98936fa586db37745535dbb01544760abe3c6398f99b6cf4130d53c4eb5136e
data/Gemfile CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- # Specify your gem's dependencies in mdocs.gemspec
6
- gemspec
7
-
8
5
  gem 'rake', '~> 13.0'
9
- gem 'simplecov', '~> 0.21'
10
6
  gem 'rspec', '~> 3.10'
11
7
  gem 'rspec_junit_formatter', '~> 0.4'
8
+ gem 'simplecov', '~> 0.21'
12
9
  gem 'simplecov-console'
13
10
 
14
11
  gem 'rubocop', require: false
12
+
13
+ # Specify your gem's dependencies in mdocs.gemspec
14
+ gemspec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- middleman-mdocs (0.1.0.62562)
4
+ middleman-mdocs (0.1.1.75132)
5
5
  activesupport
6
6
  awesome_print
7
7
  kramdown
@@ -26,12 +26,12 @@ GEM
26
26
  addressable (2.8.0)
27
27
  public_suffix (>= 2.0.2, < 5.0)
28
28
  ansi (1.5.0)
29
- asciidoctor (2.0.16)
29
+ asciidoctor (2.0.17)
30
30
  asciidoctor-plantuml (0.0.12)
31
31
  asciidoctor (>= 1.5.6, < 3.0.0)
32
32
  ast (2.4.2)
33
33
  awesome_print (1.9.2)
34
- backports (3.21.0)
34
+ backports (3.23.0)
35
35
  coffee-script (2.4.1)
36
36
  coffee-script-source
37
37
  execjs
@@ -45,8 +45,8 @@ GEM
45
45
  execjs (2.8.1)
46
46
  exifr (1.3.9)
47
47
  fast_blank (1.0.1)
48
- fastimage (2.2.5)
49
- ffi (1.15.4)
48
+ fastimage (2.2.6)
49
+ ffi (1.15.5)
50
50
  fspath (3.1.2)
51
51
  gitlab_kramdown (0.10.0)
52
52
  asciidoctor-plantuml (= 0.0.12)
@@ -71,14 +71,14 @@ GEM
71
71
  fspath (>= 2.1, < 4)
72
72
  image_optim (~> 0.19)
73
73
  image_size (1.5.0)
74
- in_threads (1.5.4)
74
+ in_threads (1.6.0)
75
75
  kramdown (2.3.1)
76
76
  rexml
77
77
  libv8 (3.16.14.19-x86_64-linux)
78
78
  listen (3.0.8)
79
79
  rb-fsevent (~> 0.9, >= 0.9.4)
80
80
  rb-inotify (~> 0.9, >= 0.9.7)
81
- mdocs_kramdown (0.1.1.47381)
81
+ mdocs_kramdown (0.1.2.70482)
82
82
  gitlab_kramdown (~> 0)
83
83
  memoist (0.16.2)
84
84
  middleman (4.3.11)
@@ -122,7 +122,7 @@ GEM
122
122
  nokogiri (~> 1.6)
123
123
  therubyracer (~> 0.12.2)
124
124
  mini_portile2 (2.4.0)
125
- minitest (5.14.4)
125
+ minitest (5.15.0)
126
126
  nokogiri (1.10.10)
127
127
  mini_portile2 (~> 2.4.0)
128
128
  padrino-helpers (0.13.3.4)
@@ -146,7 +146,7 @@ GEM
146
146
  ref (2.0.0)
147
147
  regexp_parser (2.1.1)
148
148
  rexml (3.2.5)
149
- rouge (3.26.1)
149
+ rouge (3.27.0)
150
150
  rspec (3.10.0)
151
151
  rspec-core (~> 3.10.0)
152
152
  rspec-expectations (~> 3.10.0)
@@ -199,7 +199,7 @@ GEM
199
199
  therubyracer (0.12.3)
200
200
  libv8 (~> 3.16.14.15)
201
201
  ref
202
- thor (1.1.0)
202
+ thor (1.2.1)
203
203
  thread_safe (0.3.6)
204
204
  tilt (2.0.10)
205
205
  tzinfo (1.2.9)
@@ -221,4 +221,4 @@ DEPENDENCIES
221
221
  simplecov-console
222
222
 
223
223
  BUNDLED WITH
224
- 2.2.26
224
+ 2.2.28
data/README.md CHANGED
@@ -1,3 +1,17 @@
1
1
  # MiddlemanMdocs
2
2
 
3
- В процессе...
3
+ Это шаблон для генерации статической документации. Он является расширением для проекта [Middleman](https://middlemanapp.com/) и включает некоторые улучшения и исправления.
4
+
5
+ ## Запуск
6
+
7
+ В папке [template](./template) находится шаблон рабочего проекта. Фичи:
8
+
9
+ * поддержка `UTF-8`
10
+ * полнотекстовый поиск `lunr.js`
11
+ * Динамическое оглавление страницы
12
+ * `sitemap.txt` `robots.txt` `turbo.tss`
13
+ * `Yandex Metrika`
14
+ * `Open Graph` разметка
15
+ * метаданные `tags` и `keywords` для каждой страницы
16
+ * расширемые стили `bootstrap` с двумя темами
17
+
data/bin/console CHANGED
@@ -2,7 +2,9 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'bundler/setup'
5
- require 'mdocs'
5
+ require 'middleman-mdocs'
6
+ require 'middleman-mdocs/extension'
7
+ require 'middleman-mdocs/deps'
6
8
 
7
9
  # You can add fixtures and/or initialization code here to make experimenting
8
10
  # with your gem easier. You can also use a different console, if you like.
@@ -1,38 +1,101 @@
1
1
  module MiddlemanMdocs
2
2
  class Controller
3
- attr_reader :nav, :sitemap, :app
3
+ attr_reader :nav, :extension, :sitemap, :app, :ready
4
+
5
+ include(::MiddlemanMdocs::TOC)
6
+
7
+ def initialize(extension)
8
+ @extension = extension
9
+
10
+ @app = extension.app
11
+ @sitemap = app.sitemap
4
12
 
5
- def initialize(sitemap)
6
- @sitemap = sitemap
7
- @app = sitemap.app
8
13
  @guards = {}
14
+ @dependencies = {}
15
+ @metadata = {}
16
+ @updated = SecureRandom.hex
17
+ @resources = {}
18
+ end
19
+
20
+ def register(resource)
21
+ if (old = @resources[resource.page_id])
22
+ resource.copy_from(old)
23
+ else
24
+ resource.copy_from(resource)
25
+ end
26
+
27
+ @resources[resource.page_id] = resource
28
+ end
29
+
30
+ def refresh
31
+ @updated = SecureRandom.hex
32
+ @ready = true
33
+ end
34
+
35
+ def nav
36
+ with_cache(:nav) do
37
+ ::MiddlemanMdocs::Navigation.parse(app.data.mdocs['nav'])
38
+ end
39
+ end
40
+
41
+ def ready?
42
+ @ready
43
+ end
44
+
45
+ def add_dependency(resource, child)
46
+ @dependencies[resource.page_id] ||= {}
47
+ @dependencies[resource.page_id][child.page_id] = child
48
+ end
49
+
50
+ def dependencies(resource)
51
+ @dependencies[resource.page_id]&.values || []
52
+ end
53
+
54
+ def metadata(resource, key, default)
55
+ @metadata[resource.page_id] ||= {}
56
+ @metadata[resource.page_id][key] ||= default
57
+ end
58
+
59
+ def set_metadata(resource, key, data)
60
+ @metadata[resource.page_id] ||= {}
61
+ @metadata[resource.page_id][key] = data
62
+ end
63
+
64
+ def page_id
65
+ self.class.to_s
9
66
  end
10
67
 
11
- def load(mdocs)
12
- @nav = ::MiddlemanMdocs::Navigation.parse(mdocs['nav'])
68
+ def init_resource(resource)
69
+ resource.extend(::MiddlemanMdocs::Resource) unless resource.is_a?(::MiddlemanMdocs::Resource)
70
+ resource.extension = extension
71
+ resource.mdocs = self
13
72
  end
14
73
 
15
74
  def tags
16
- sitemap.resources.select { |r| r.is_a?(::MiddlemanMdocs::Resource) }.map do |r|
17
- guard_recursive('tags', r.path, []) do |_key|
75
+ with_cache(:tags, dependencies(self).map(&:timestamp).max) do
76
+ sitemap.resources.select do |r|
77
+ r.is_a?(::MiddlemanMdocs::Resource) && !r.metadata[:ignore] && r.html?
78
+ end.map do |r|
79
+ add_dependency(self, r)
80
+ # r.options[:tags]
18
81
  r.tags
19
- end
20
- end.flatten.compact.map(&:to_sym).uniq
82
+ end.flatten.compact.map(&:to_s).uniq.sort
83
+ end
21
84
  end
22
85
 
23
86
  def has_tag?(tag)
24
- tags.include?(tag.to_sym)
87
+ tags.include?(tag.to_s)
25
88
  end
26
89
 
27
90
  def select_by_meta(meta)
28
91
  with_ensure_resource do
29
- if meta.is_a? Hash
30
- sitemap.resources.select do |resource|
31
- resource.is_a?(::MiddlemanMdocs::Resource) && resource.meta_match?(meta) && resource.template?
32
- end
33
- else
34
- sitemap.resources.select do |resource|
35
- resource.is_a?(::MiddlemanMdocs::Resource) && resource.has_meta?(*meta) && resource.template?
92
+ sitemap.resources.select do |r|
93
+ next false unless r.is_a?(::MiddlemanMdocs::Resource) && !r.metadata[:ignore] && r.template?
94
+
95
+ if meta.is_a? Hash
96
+ r.meta_match?(meta)
97
+ else
98
+ r.has_meta?(*meta)
36
99
  end
37
100
  end
38
101
  end
@@ -40,29 +103,35 @@ module MiddlemanMdocs
40
103
 
41
104
  def select_by_meta_force(meta)
42
105
  with_ensure_resource do
43
- if meta.is_a? Hash
44
- sitemap.resources.select do |resource|
45
- resource.is_a?(::MiddlemanMdocs::Resource) && resource.meta_match?(meta)
46
- end
47
- else
48
- sitemap.resources.select do |resource|
49
- resource.is_a?(::MiddlemanMdocs::Resource) && resource.has_meta?(*meta)
106
+ sitemap.resources.select do |r|
107
+ next false unless r.is_a?(::MiddlemanMdocs::Resource) && !r.metadata[:ignore]
108
+
109
+ if meta.is_a? Hash
110
+ r.meta_match?(meta)
111
+ else
112
+ r.has_meta?(*meta)
50
113
  end
51
114
  end
52
115
  end
53
116
  end
54
117
 
55
118
  def select_by_tags(*tags)
119
+ tags = [tags].flatten.compact.uniq
120
+
56
121
  with_ensure_resource do
57
- sitemap.resources.select do |resource|
58
- resource.is_a?(::MiddlemanMdocs::Resource) && resource.has_tags?(*tags) && resource.template?
122
+ sitemap.resources.select do |r|
123
+ next false unless r.is_a?(::MiddlemanMdocs::Resource) && !r.metadata[:ignore] && r.template?
124
+
125
+ r.has_tags?(*tags)
59
126
  end
60
127
  end
61
128
  end
62
129
 
63
130
  def select(tags, *meta)
64
- select_by_meta(*meta).select do |resource|
65
- resource.is_a?(::MiddlemanMdocs::Resource) && resource.has_tags?(*tags) && resource.template?
131
+ tags = [tags].flatten.compact.uniq
132
+
133
+ select_by_meta(*meta).select do |r|
134
+ r.has_tags?(*tags)
66
135
  end
67
136
  end
68
137
 
@@ -76,10 +145,20 @@ module MiddlemanMdocs
76
145
  end
77
146
 
78
147
  def tr(tag, scope: :tags)
148
+ ::MiddlemanMdocs::Controller.tr(tag, scope: scope)
149
+ end
150
+
151
+ def self.tr(tag, scope: :tags)
79
152
  I18n.t(tag.to_s.upcase.presence, scope: [:mdocs, scope],
80
153
  default: I18n.t(tag.to_s.downcase.presence, scope: [:mdocs, scope], default: tag.to_s).presence)
81
154
  end
82
155
 
156
+ private
157
+
158
+ def with_cache(*key, &block)
159
+ extension.cache.fetch([:controller, @updated, *key], &block)
160
+ end
161
+
83
162
  def guard_recursive(name, key, default = nil)
84
163
  guard = @guards[name] ||= {}
85
164
  return guard[key] if guard.has_key?(key)
@@ -0,0 +1,12 @@
1
+ require 'kramdown/parser'
2
+ require 'kramdown/converter'
3
+
4
+ require 'mdocs_kramdown'
5
+ require 'kramdown/parser/mdocs_kramdown'
6
+
7
+ require_relative 'resource'
8
+ require_relative 'toc'
9
+ require_relative 'tilt_template'
10
+ require_relative 'navigation'
11
+ require_relative 'controller'
12
+ require_relative 'sitemap'
@@ -1,37 +1,57 @@
1
+ require 'active_support/cache'
2
+ require 'active_support/cache/memory_store'
3
+
4
+ require 'middleman-core/util'
5
+ require 'middleman-core/util/files'
6
+
7
+ module Middleman
8
+ module Util
9
+ include Contracts
10
+
11
+ module_function
12
+
13
+ # Finds files which should also be considered to be dirty when
14
+ # the given file(s) are touched.
15
+ #
16
+ # @param [Middleman::Application] app The app.
17
+ # @param [Pathname] files The original touched file paths.
18
+ # @return [Middleman::SourceFile] All related file paths, not including the source file paths.
19
+ Contract ::Middleman::Application, ArrayOf[Pathname] => ArrayOf[::Middleman::SourceFile]
20
+ def find_related_files(_app, _files)
21
+ []
22
+ end
23
+ end
24
+ end
25
+
1
26
  module MiddlemanMdocs
2
27
  class Extension < Middleman::Extension
3
28
  attr_reader :mdocs, :mdocsnav, :mdocsmeta
4
29
 
30
+ cattr_reader :cache
31
+
5
32
  expose_to_application :mdocs, :mdocsnav
6
33
  expose_to_template :mdocs, :mdocsnav
34
+
7
35
  expose_to_config :mdocs, :enrich_metadata
36
+ expose_to_config :mdocs, :static_sitemap
8
37
 
9
38
  def initialize(*args, **_kwargs, &block)
10
39
  super
11
40
 
12
41
  # Only require dependency on activation
13
- require 'kramdown/parser'
14
- require 'kramdown/converter'
15
-
16
- require 'mdocs_kramdown'
17
- require 'kramdown/parser/mdocs_kramdown'
42
+ require_relative 'deps'
18
43
 
19
- require_relative 'resource'
20
- require_relative 'toc'
21
- require_relative 'tilt_template'
22
- require_relative 'navigation'
23
- require_relative 'controller'
24
- require_relative 'sitemap'
44
+ # @@cache ||= ActiveSupport::Cache::MemoryStore.new(size: 100.megabytes)
45
+ @@cache ||= ActiveSupport::Cache::FileStore.new('tmp/mdocs/cache')
25
46
 
26
- @mdocs = Controller.new(app.sitemap)
47
+ register_helpers(::MiddlemanMdocs::Navigation)
27
48
 
28
49
  configure_application
29
50
 
30
- register_helpers(::MiddlemanMdocs::TOC)
31
- register_helpers(::MiddlemanMdocs::Navigation)
32
-
33
51
  @mdocsmeta = {}
34
52
 
53
+ @mdocs = Controller.new(self)
54
+
35
55
  ::ActiveSupport::Notifications.subscribe('sitemap.update.middleman') do
36
56
  lookup = @mdocs.sitemap.instance_variable_get('@_lookup_by_destination_path')
37
57
  @mdocs.sitemap.resources.each do |resource|
@@ -41,7 +61,7 @@ module MiddlemanMdocs
41
61
  end
42
62
 
43
63
  def configure_application
44
- ::Middleman::Sitemap::Store.include(::MiddlemanMdocs::Sitemap)
64
+ Middleman::Sitemap::Store.include(::MiddlemanMdocs::Sitemap)
45
65
 
46
66
  app.config[:markdown_engine] = :kramdown
47
67
  app.config[:markdown] = {
@@ -67,9 +87,34 @@ module MiddlemanMdocs
67
87
  end
68
88
  end
69
89
 
90
+ def after_build
91
+ $app = app
92
+ if @sitemap_opts && @sitemap_block
93
+ interpreter = SitemapGenerator::Interpreter.new(@sitemap_opts.merge(compress: true))
94
+ interpreter.instance_eval(&@sitemap_block)
95
+
96
+ interpreter = SitemapGenerator::Interpreter.new(@sitemap_opts.merge(compress: false))
97
+ interpreter.instance_eval(&@sitemap_block)
98
+ end
99
+ end
100
+
70
101
  def after_configuration
71
102
  markdown_exts = %w[markdown mdown md mkd mkdn]
72
- ::Tilt.register ::MiddlemanMdocs::TiltTempalte, *markdown_exts
103
+ ::Tilt.register ::MiddlemanMdocs::TiltTemplate, *markdown_exts
104
+
105
+ app.files.on_change :source do |changed, _deleted|
106
+ resources = changed.map do |_ch|
107
+ full = changed.first.full_path.to_s
108
+ app.sitemap.resources.find { |r| r.source_file == full }
109
+ end.flatten
110
+
111
+ resources.compact.each(&:refresh)
112
+ end
113
+ end
114
+
115
+ def static_sitemap(opts = {}, &block)
116
+ @sitemap_opts = opts = opts.dup
117
+ @sitemap_block = block
73
118
  end
74
119
 
75
120
  def enrich_metadata(rx, &block)
@@ -77,18 +122,17 @@ module MiddlemanMdocs
77
122
  @enrichers.push([rx, block])
78
123
  end
79
124
 
80
- def ready
81
- mdocs.load(app.data.mdocs)
125
+ helpers do
82
126
  end
83
127
 
84
- helpers do
128
+ def log(text)
129
+ logger.debug "[MDOCS] #{Time.now}: #{text}"
85
130
  end
86
131
 
87
132
  def manipulate_resource_list(resources)
133
+ logger.debug '== [MDOCS] enrich resources...'
88
134
  resources.each do |resource|
89
- # install MdDocs::Resource extension
90
- resource.extend(::MiddlemanMdocs::Resource) unless resource.is_a?(::MiddlemanMdocs::Resource)
91
- resource.mdocs_extention = self
135
+ mdocs.init_resource(resource)
92
136
 
93
137
  next if resource.metadata[:ignore]
94
138
 
@@ -98,8 +142,15 @@ module MiddlemanMdocs
98
142
  resource.destination_path << '.html' unless resource.destination_path.end_with?('.html')
99
143
  end
100
144
 
101
- resource.add_tags(*resource.data.tags)
102
- resource.add_keywords(*resource.data.keywords)
145
+ mdocs.register(resource)
146
+
147
+ nonce = SecureRandom.hex
148
+
149
+ state = cache.fetch([resource.cache_key, :manipulate_resource_list]) do
150
+ nonce
151
+ end
152
+
153
+ next if mdocs.ready? && nonce != state
103
154
 
104
155
  # enrich recursive metadata from metadata.yml in each folder
105
156
  metadata = get_metadata(resource.source_file)
@@ -111,21 +162,24 @@ module MiddlemanMdocs
111
162
  block.call(resource, md)
112
163
  end
113
164
  end
165
+
166
+ resource.refresh
114
167
  end
115
168
 
169
+ mdocs.refresh
116
170
  resources
117
171
  end
118
172
 
119
173
  def get_metadata(path)
120
174
  return {} unless path[app.source_dir.to_s]
121
175
 
122
- path = ::Pathname.new(path)
176
+ path = Pathname.new(path)
123
177
  current_dir = path.dirname.relative_path_from(app.source_dir).to_s
124
178
 
125
179
  @mdocsmeta[current_dir] || begin
126
180
  tokens = current_dir.split('/')
127
181
 
128
- ([''] + tokens).reduce(::Pathname('')) do |parent, token|
182
+ ([''] + tokens).reduce(Pathname('')) do |parent, token|
129
183
  return {} if ['.', ','].include?(token)
130
184
 
131
185
  current = parent.join(token)
@@ -76,7 +76,7 @@ module MiddlemanMdocs
76
76
  if block_given?
77
77
  link_to("/tags/#{tag}", *args, &block)
78
78
  else
79
- link_to(I18n.t(tag, scope: %i[mdocs tags], default: tag.to_s), "/tags/#{tag}.html", *args, &block)
79
+ link_to(I18n.t(tag, scope: %i[mdocs tags], default: tag.to_s), "/tags/#{tag}", *args, &block)
80
80
  end
81
81
  end
82
82
 
@@ -85,28 +85,42 @@ module MiddlemanMdocs
85
85
  url.try(:source_file)
86
86
  elsif url.start_with?('/')
87
87
  app.source_dir.join(url[1..-1]).to_s
88
+ elsif current_page
89
+ Pathname.new(current_page.source_file).dirname.join(url).to_s
88
90
  else
89
- ::Pathname.new(current_page.source_file).dirname.join(url).to_s
91
+ url
90
92
  end
91
93
  app.sitemap.resources.find { |r| r.source_file == source_file }
92
94
  end
93
95
 
94
96
  def merge(url)
95
- resource = fuzzy_find_resource(url)
97
+ resource = fuzzy_find_resource(url) || sitemap.find_resource_by_page_id(url)
96
98
  raise "unable to find resource by #{url}" unless resource
97
99
 
98
- current_page.add_tags(*resource.data.fetch(:tags, []))
99
- current_page.data.reverse_merge!(resource.data)
100
+ mdocs.init_resource(resource) unless resource.is_a?(::MiddlemanMdocs::Resource)
101
+ if current_page
102
+ current_page.add_tags(resource.tags)
103
+ current_page.add_keywords(resource.keywords)
104
+ current_page.data.reverse_merge!(resource.data)
105
+ end
100
106
  end
101
107
 
102
108
  def include(page_id_or_path, merge: true, render: true)
103
- merge(page_id_or_path) if merge
104
109
  resource = fuzzy_find_resource(page_id_or_path) || sitemap.find_resource_by_page_id(page_id_or_path)
105
- if render
106
- resource.render(layout: false)
107
- else
108
- ::File.read(resource.try(:source_file) || page_id_or_path)
109
- end
110
+ mdocs.add_dependency(current_page, resource)
111
+
112
+ mdocs.init_resource(resource) unless resource.is_a?(::MiddlemanMdocs::Resource)
113
+ result = if render
114
+ resource.force_render
115
+ else
116
+ ::File.read(resource.try(:source_file) || page_id_or_path)
117
+ end
118
+
119
+ merge(page_id_or_path) if merge
120
+ result
121
+ rescue StandardError => e
122
+ puts "Error on including #{page_id_or_path.inspect} to #{current_page.inspect}: #{e.inspect}"
123
+ raise
110
124
  end
111
125
 
112
126
  # some custom magic to find result path to generated resource
@@ -121,6 +135,15 @@ module MiddlemanMdocs
121
135
  end
122
136
  end
123
137
 
138
+ def current_page
139
+ r = super
140
+ if r.nil?
141
+ @locs&.fetch(:force_current_page, nil)
142
+ else
143
+ r
144
+ end
145
+ end
146
+
124
147
  # is this is url for current page
125
148
  def active_url?(url)
126
149
  translated = translate_to_destination(url)
@@ -1,57 +1,150 @@
1
1
  module MiddlemanMdocs
2
2
  module Resource
3
- attr_accessor :mdocs_extention
3
+ attr_accessor :extension, :mdocs, :updated
4
+
5
+ def self.normalize_tags(*args)
6
+ args.flatten.compact.map(&:to_s).map do |tag|
7
+ ::MiddlemanMdocs::Controller.tr(tag)
8
+ end.map(&:upcase).uniq.sort
9
+ end
10
+
11
+ def self.normalize_keywords(*args)
12
+ raw = args.flatten.compact.map(&:to_s)
13
+ normalized = normalize_tags(raw)
14
+ (raw + normalized).uniq.sort
15
+ end
4
16
 
5
17
  def markdown?
6
- true
18
+ metadata[:markdown]
7
19
  end
8
20
 
9
- def add_options(opts)
10
- options.deep_merge!(opts)
21
+ def html?
22
+ @html ||= destination_path.end_with?('.html')
11
23
  end
12
24
 
13
- def add_meta(opts)
14
- metadata.deep_merge!(opts)
25
+ def ready?
26
+ mdocs.ready?
15
27
  end
16
28
 
17
- def add_tags(*args)
18
- tags = (options[:tags] ||= [])
19
- tags.append(*args.map(&:to_sym))
20
- tags = tags.map(&:to_s).map(&:upcase).uniq.map(&:to_sym)
21
- options[:tags] = tags
29
+ def copy_from(other)
30
+ resource = self
31
+ unless @patched
32
+ data.define_singleton_method(:title) do
33
+ resource.title
34
+ end
22
35
 
23
- add_keywords(*args)
24
- add_keywords(*args.map { |tag| I18n.t(tag, scope: %i[mdocs tags], default: tag.to_s) })
36
+ data.define_singleton_method(:keywords) do
37
+ resource.keywords
38
+ end
39
+
40
+ data.define_singleton_method(:text) do
41
+ resource.text
42
+ end
43
+
44
+ @patched = true
45
+ end
46
+
47
+ custom_deep_merge!(data, other.data)
48
+ custom_deep_merge!(metadata, other.metadata)
49
+
50
+ self.updated = other.updated
25
51
  end
26
52
 
27
- def add_keywords(*args)
28
- keywords = (options[:keywords] ||= [])
29
- keywords.append(*args.map(&:to_s))
30
- keywords.uniq!
53
+ def updated_at
54
+ @updated_at ||= begin
55
+ ts = data[:updated_at] || metadata[:updated_at] || timestamp
56
+ ts = DateTime.parse(ts) if ts.is_a?(String)
57
+ ts
58
+ end
31
59
  end
32
60
 
33
- def tags
34
- unless @rendered
35
- unless metadata[:ignore]
36
- begin
37
- render(layout: false)
38
- rescue StandardError
39
- nil
40
- end
41
- end
42
- @rendered = true
61
+ def created_at
62
+ @created_at ||= begin
63
+ ts = data[:created_at] || metadata[:created_at] || File.ctime(source_file)
64
+ ts = DateTime.parse(ts) if ts.is_a?(String)
65
+ [ts, updated_at].min
43
66
  end
44
- (options[:tags] ||= [])
67
+ end
68
+
69
+ def timestamp
70
+ (mdocs.dependencies(self).map(&:timestamp) + [File.mtime(source_file)]).max
71
+ end
72
+
73
+ def cache_key
74
+ "#{page_id}/#{timestamp}/"
45
75
  end
46
76
 
47
77
  def title
48
- return nil unless metadata[:markdown]
78
+ with_cache(:title, @updated) do
79
+ data[:title] || metadata[:title] || toc&.children&.first&.raw_text
80
+ end
81
+ end
49
82
 
50
- data[:title] ||= @mdocs_extention.table_of_contents(self).children.first&.raw_text
83
+ def refresh
84
+ @guards ||= {}
85
+
86
+ # @updated = SecureRandom.hex
87
+ end
88
+
89
+ def text
90
+ force_render if !metadata[:ignore] && html?
91
+ end
92
+
93
+ def tags
94
+ with_cache(:tags, @updated) do
95
+ guard_recursive('tags', page_id, []) do |_key|
96
+ text
97
+ end
98
+
99
+ options[:tags] = ::MiddlemanMdocs::Resource.normalize_tags(options[:tags], data[:tags], metadata[:tags])
100
+ end
51
101
  end
52
102
 
53
103
  def keywords
54
- (options[:keywords] ||= [])
104
+ with_cache(:keywords, @updated) do
105
+ options[:keywords] =
106
+ ::MiddlemanMdocs::Resource.normalize_keywords(tags, options[:keywords], data[:keywords], metadata[:keywords])
107
+ end
108
+ end
109
+
110
+ def toc
111
+ with_cache(:toc, @updated) do
112
+ if metadata[:ignore] || !html?
113
+ nil
114
+ else
115
+ mdocs.table_of_contents(self)
116
+ end
117
+ end
118
+ end
119
+
120
+ def add_options(opts)
121
+ options.deep_merge!(opts)
122
+ end
123
+
124
+ def add_meta(opts)
125
+ metadata.deep_merge!(opts)
126
+ end
127
+
128
+ def add_tags(*args)
129
+ return unless args.flatten.any?
130
+
131
+ added = ::MiddlemanMdocs::Resource.normalize_tags(args)
132
+ return if (added - (options[:tags] || [])).empty?
133
+
134
+ @updated = SecureRandom.hex
135
+ options[:tags] = ::MiddlemanMdocs::Resource.normalize_tags(options[:tags], data[:tags], metadata[:tags], added)
136
+ end
137
+
138
+ def add_keywords(*args)
139
+ return unless args.flatten.any?
140
+
141
+ added = ::MiddlemanMdocs::Resource.normalize_keywords(args)
142
+ return if (added - (options[:keywords] || [])).empty?
143
+
144
+ @updated = SecureRandom.hex
145
+ options[:keywords] =
146
+ ::MiddlemanMdocs::Resource.normalize_keywords(options[:tags], options[:keywords], data[:keywords], metadata[:keywords],
147
+ added)
55
148
  end
56
149
 
57
150
  def meta_match?(meta)
@@ -67,9 +160,60 @@ module MiddlemanMdocs
67
160
  end
68
161
 
69
162
  def has_tags?(*keys)
70
- keys.compact!
71
- keys.uniq!
72
163
  (tags & keys).size == keys.size
73
164
  end
165
+
166
+ def destination_path(*args)
167
+ super.force_encoding(Encoding.default_external)
168
+ end
169
+
170
+ def force_render
171
+ render({ layout: false }, { current_path: path, force_current_page: self })
172
+ end
173
+
174
+ def render(opts = {}, locs = {})
175
+ return super if nocache? || locs.has_key?('rack') || locs.has_key?(:rack)
176
+
177
+ with_cache(Digest::MD5.hexdigest(opts.to_json + locs.to_json) + 'render') do
178
+ # puts "REFRESH: #{binary?} #{page_id}: #{opts.to_json + locs.to_json}"
179
+ super
180
+ end
181
+ end
182
+
183
+ private
184
+
185
+ def nocache?
186
+ binary? || metadata[:ignore] || metadata[:nocache] || data[:nocache]
187
+ end
188
+
189
+ def with_cache(*key, &block)
190
+ extension.cache.fetch([cache_key, *key], &block)
191
+ end
192
+
193
+ def custom_deep_merge!(left, right)
194
+ left.merge!(right) do |_key, this_val, other_val|
195
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
196
+ custom_deep_merge!(this_val, other_val)
197
+ elsif this_val.is_a?(Array) && other_val.is_a?(Array)
198
+ this_val.concat(other_val).uniq!
199
+ else
200
+ other_val.nil? ? this_val : other_val
201
+ end
202
+ end
203
+ end
204
+
205
+ def guard_recursive(name, key, default = nil)
206
+ @guards ||= {}
207
+
208
+ guard = @guards[name] ||= {}
209
+ return guard[key] if guard.has_key?(key)
210
+
211
+ begin
212
+ guard[key] = default
213
+ guard[key] = yield(key)
214
+ ensure
215
+ guard.delete(key)
216
+ end
217
+ end
74
218
  end
75
219
  end
@@ -1,7 +1,7 @@
1
1
  require 'middleman-core/renderers/kramdown'
2
2
 
3
3
  module MiddlemanMdocs
4
- class TiltTempalte < ::Middleman::Renderers::KramdownTemplate
4
+ class TiltTemplate < ::Middleman::Renderers::KramdownTemplate
5
5
  def render(*args)
6
6
  erb = Middleman::Renderers::ERb::Template.new(file, line, options) { data }
7
7
  @data = erb.render(*args)
@@ -50,10 +50,13 @@ module MiddlemanMdocs
50
50
  ## Generate TOC object tree for current page or source file
51
51
  #
52
52
  def table_of_contents(page_or_source, input: 'markdown')
53
+ # puts "#{Process.pid} =>>>> GENERATE TOC: #{page_or_source.try(:page_id) || page_or_source}"
54
+ # byebug if page_or_source.page_id.force_encoding('UTF-8') == 'docs/services/gis-gmp/import-refunds'
55
+
53
56
  begin
54
57
  return nil if page_or_source.metadata[:ignore]
55
58
 
56
- content = page_or_source.render(layout: false)
59
+ content = page_or_source.text
57
60
  toc = Kramdown::Document.new(content, app.config[:markdown].merge(input: 'html')).to_toc
58
61
 
59
62
  return Item.parse_kramdown_toc(toc)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MiddlemanMdocs
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: middleman-mdocs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.62562
4
+ version: 0.1.1.75132
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samoylenko Yuri
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-09-24 00:00:00.000000000 Z
12
+ date: 2022-02-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -194,6 +194,7 @@ files:
194
194
  - bin/setup
195
195
  - lib/middleman-mdocs.rb
196
196
  - lib/middleman-mdocs/controller.rb
197
+ - lib/middleman-mdocs/deps.rb
197
198
  - lib/middleman-mdocs/extension.rb
198
199
  - lib/middleman-mdocs/navigation.rb
199
200
  - lib/middleman-mdocs/resource.rb