client_pages 0.0.2.alpha → 0.0.3.beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.rubocop.yml +74 -0
- data/README.md +19 -46
- data/Rakefile +8 -1
- data/client_pages.gemspec +1 -0
- data/lib/client_pages/configuration.rb +29 -0
- data/lib/client_pages/markdown_content/content_builder.rb +64 -0
- data/lib/client_pages/markdown_content/renderer.rb +84 -0
- data/lib/client_pages/matcher.rb +39 -0
- data/lib/client_pages/template.rb +7 -0
- data/lib/client_pages/version.rb +1 -1
- data/lib/client_pages.rb +14 -196
- data/spec/fixtures/{link_list.md → content/link_list.md} +0 -0
- data/spec/fixtures/{test_content.md → content/test_content.md} +0 -0
- data/spec/fixtures/{text_list.md → content/text_list.md} +0 -0
- data/spec/fixtures/foo/bar.md +3 -0
- data/spec/integration/client_pages_spec.rb +274 -0
- data/spec/spec_helper.rb +24 -1
- data/spec/unit/configuration_spec.rb +52 -0
- data/spec/unit/content_builder_spec.rb +8 -0
- data/spec/unit/matcher_spec.rb +11 -0
- data/spec/unit/renderer_spec.rb +8 -0
- data/spec/unit/template_spec.rb +16 -0
- metadata +42 -10
- data/spec/unit/client_pages_spec.rb +0 -205
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 651585c4dbeab42b84039c22aec54878b9f54426
|
4
|
+
data.tar.gz: df24efef446ba402721bf025295c0d978103dfd4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f859d580c6ba704bec2fd9dcbb05baa4208bae91c355c6c8618f55d9a46ce32bceeaa0b4bab8622ca4b2279dcd7a6d577908a33bfc664e39e4b391b122071d6
|
7
|
+
data.tar.gz: 9812ecd03067ce9907d6fe3d0c1fd58d6625877fb1f2d44a67af5ec5535e373187abc1aa4313cb82db0184968cf472ffa59c32d0d4b14a459988942aecad49f2
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
AllCops:
|
2
|
+
Includes:
|
3
|
+
- 'Gemfile'
|
4
|
+
- 'Rakefile'
|
5
|
+
|
6
|
+
ParameterLists:
|
7
|
+
Max: 3
|
8
|
+
CountKeywordArgs: true
|
9
|
+
|
10
|
+
BlockNesting:
|
11
|
+
Max: 3
|
12
|
+
|
13
|
+
HashSyntax:
|
14
|
+
Enabled: true
|
15
|
+
|
16
|
+
StringLiterals:
|
17
|
+
Enabled: true
|
18
|
+
|
19
|
+
Void:
|
20
|
+
Enabled: true
|
21
|
+
|
22
|
+
LineLength:
|
23
|
+
Enabled: true
|
24
|
+
Max: 115
|
25
|
+
|
26
|
+
CyclomaticComplexity:
|
27
|
+
Max: 7
|
28
|
+
|
29
|
+
SpaceInsideHashLiteralBraces:
|
30
|
+
Enabled: true
|
31
|
+
|
32
|
+
AlignParameters:
|
33
|
+
Enabled: true
|
34
|
+
|
35
|
+
Blocks:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
SpaceAroundEqualsInParameterDefault:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
NumericLiterals:
|
42
|
+
Enabled: true
|
43
|
+
|
44
|
+
SpaceInsideBrackets:
|
45
|
+
Enabled: true
|
46
|
+
|
47
|
+
WordArray:
|
48
|
+
Enabled: true
|
49
|
+
|
50
|
+
Lambda:
|
51
|
+
Enabled: true
|
52
|
+
|
53
|
+
RegexpLiteral:
|
54
|
+
Enabled: true
|
55
|
+
|
56
|
+
ConstantName:
|
57
|
+
Enabled: false
|
58
|
+
|
59
|
+
TrivialAccessors:
|
60
|
+
Enabled: true
|
61
|
+
ExactNameMatch: true
|
62
|
+
|
63
|
+
Alias:
|
64
|
+
Enabled: true
|
65
|
+
|
66
|
+
Loop:
|
67
|
+
Enabled: true
|
68
|
+
|
69
|
+
AndOr:
|
70
|
+
Enabled: false
|
71
|
+
|
72
|
+
Documentation:
|
73
|
+
Enabled: false
|
74
|
+
|
data/README.md
CHANGED
@@ -1,47 +1,19 @@
|
|
1
1
|
# ClientPages
|
2
2
|
|
3
|
-
##### Todo:
|
4
|
-
|
5
|
-
- extract single files and responsibilites
|
6
|
-
- set resonable defaults, like enable table, and auto link.
|
7
|
-
- fallback option? => error handling if no such file?
|
8
|
-
- yaml content?
|
9
|
-
- builder#wrap needs conditional and multi wrap + nested wrap
|
10
|
-
- builder methoden vereinheitlichen
|
11
|
-
- modify :tag, with: {}, if: {}|->|?
|
12
|
-
- wrap :tag, with: {}, if: {}|->|?
|
13
|
-
- replace :tag, with: {}, if: {}|->|?
|
14
|
-
- c.method &block
|
15
|
-
- builder defaults? (all :p will get class x)
|
16
|
-
- maybe adjust ```render_content``` with additional parameter, like simple_form does
|
17
|
-
- defaults: :table_settings => will be stored somewhere as a block
|
18
|
-
- test new configs! (.remote, .remote_content_path, .content_path, .caching, .fallback, .i18n)
|
19
|
-
- railtie
|
20
|
-
- i18n support content/de/something, content/en/something
|
21
|
-
- extract classes
|
22
|
-
- oauth dropbox?
|
23
|
-
- logger!?
|
24
|
-
- back up command/rake task, content:pull
|
25
|
-
nimmt alle local content files und überschreibt diese mit denen der remote version (wenn verfügbar)
|
26
|
-
- travis
|
27
|
-
- codeclimate
|
28
|
-
|
29
|
-
|
30
|
-
if defined?(Rails)
|
31
|
-
html_safe all the things
|
32
|
-
|
33
3
|
---
|
4
|
+
Ever heard: **"can we change the text on the homepage by ourself?"**
|
34
5
|
|
35
|
-
|
36
|
-
|
37
|
-
---
|
6
|
+
___
|
38
7
|
|
39
|
-
with client_pages you can separate your content from html markup and css styles
|
8
|
+
with client_pages you can separate your content from html markup and css styles,
|
9
|
+
by extracting it to simple markdown files.
|
40
10
|
|
41
11
|
use it for small content parts of your app which need to be updated regulary by someone
|
42
12
|
or outsource all your content together, it's up to you.
|
43
13
|
|
44
|
-
|
14
|
+
"the principle is really easy. at the place where you call render_content(:foo),
|
15
|
+
the renderer will grap the markdown file content/foo.md and render it as html.
|
16
|
+
by passing a block to render_content the generated markup can be modified."
|
45
17
|
|
46
18
|
the main benefit of doing this: anybody can change the content, without the need for an admin backend and stuff like this.
|
47
19
|
just make it possible for them to edit the files.
|
@@ -70,6 +42,8 @@ we can accomplish all that by just giving the ```render_content(:file)``` method
|
|
70
42
|
and tell the content builder to do that for you.
|
71
43
|
**insert haml here**
|
72
44
|
|
45
|
+
if configured ```render_content``` work with raw markdown, instead of a file name.
|
46
|
+
|
73
47
|
this way, you can add a lot of behaivour by leaving your markdown content just as content with raw structure,
|
74
48
|
and the main markup and styling stays in your views.
|
75
49
|
|
@@ -139,8 +113,6 @@ sinatra?
|
|
139
113
|
c.remote_content_path = 'https://dl.dropboxusercontent.com/u/363312/rackedy_rack'
|
140
114
|
c.content_path = 'content'
|
141
115
|
c.caching = true
|
142
|
-
c.fallback = false
|
143
|
-
c.i18n = false
|
144
116
|
c.render_options = {
|
145
117
|
hard_wrap: true,
|
146
118
|
with_toc_data: false,
|
@@ -164,17 +136,15 @@ sinatra?
|
|
164
136
|
hm, or where is the problem? ```render_content("#{my_locale}/posts/index")```
|
165
137
|
|
166
138
|
### caching
|
167
|
-
the current implementation it the easiest way to do
|
168
|
-
it's really simple and lives as long as the process runs.
|
169
|
-
it can not be shared between processes
|
139
|
+
the current implementation it the easiest way to do something like caching.
|
140
|
+
it's really simple and lives as long as the process runs, as it's nothing more than a hash that doesn't get persistet.
|
141
|
+
so it can not be shared between processes.
|
170
142
|
and because one of the [hard things in Computer Science](http://martinfowler.com/bliki/TwoHardThings.html) is _cache invalidation_
|
171
|
-
you can flush the cache also at runtime
|
172
|
-
|
173
|
-
you can accomplish this with some additional code.
|
143
|
+
you can flush the cache also at runtime with
|
174
144
|
|
175
|
-
```
|
145
|
+
```cache.clear```
|
176
146
|
|
177
|
-
|
147
|
+
So if your're curious about caching, you should take care of that by yourself and cache the complete render_content block for example.
|
178
148
|
|
179
149
|
### commands
|
180
150
|
- downloader!!!
|
@@ -184,9 +154,12 @@ sinatra?
|
|
184
154
|
|
185
155
|
## Contributing
|
186
156
|
|
157
|
+
Contributions are always welcome! Doesn't matter if you fix just a typo, add some documentation/tests or refactor hole parts of the code.
|
158
|
+
As this gem is in early development, there are a lot of low hanging fruits.
|
159
|
+
|
187
160
|
+ Fork it
|
188
161
|
+ Change it
|
189
162
|
+ Test it
|
190
163
|
+ Commit it
|
191
164
|
+ Push it
|
192
|
-
+ Pull Request
|
165
|
+
+ Pull Request it
|
data/Rakefile
CHANGED
@@ -2,4 +2,11 @@ require 'bundler/gem_tasks'
|
|
2
2
|
require 'rspec/core/rake_task'
|
3
3
|
|
4
4
|
RSpec::Core::RakeTask.new(:spec)
|
5
|
-
task default: :
|
5
|
+
task default: :metrics
|
6
|
+
|
7
|
+
desc 'run some metric tools'
|
8
|
+
task metrics: :spec do
|
9
|
+
system('rubocop')
|
10
|
+
puts
|
11
|
+
system('flog lib')
|
12
|
+
end
|
data/client_pages.gemspec
CHANGED
@@ -30,5 +30,6 @@ Gem::Specification.new do |s|
|
|
30
30
|
s.add_development_dependency 'webmock', '~> 1.17.3'
|
31
31
|
s.add_development_dependency 'pry-plus', '~> 1.0.0'
|
32
32
|
s.add_development_dependency 'rubocop', '~> 0.18.1'
|
33
|
+
s.add_development_dependency 'flog', '~> 4.2.0'
|
33
34
|
s.add_development_dependency 'simplecov', '~> 0.8.2'
|
34
35
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ClientPages
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :content_path, :remote, :remote_content_path, :caching, :fallback, :i18n, :raw_markdown
|
4
|
+
attr_reader :render_options, :markdown_extensions
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@content_path = 'content'
|
8
|
+
@render_options = {}
|
9
|
+
@markdown_extensions = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def render_options=(options)
|
13
|
+
@render_options.merge!(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def markdown_extensions=(options)
|
17
|
+
@markdown_extensions.merge!(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
# TODO: instance vars get
|
22
|
+
{
|
23
|
+
content_path: content_path,
|
24
|
+
render_options: render_options,
|
25
|
+
markdown_extensions: markdown_extensions
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module ClientPages
|
2
|
+
module MarkdownContent
|
3
|
+
class ContentBuilder
|
4
|
+
attr_accessor :html
|
5
|
+
|
6
|
+
def initialize(html)
|
7
|
+
@html = html
|
8
|
+
end
|
9
|
+
|
10
|
+
def modify(tag, options={})
|
11
|
+
html_lines do |line|
|
12
|
+
conditions(tag, line, options[:if]) do
|
13
|
+
match(tag, line, :open) { |open_tag| open_tag.gsub(/>/, "#{attributes(options)}>") }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def wrap(tag, wrapper, options={})
|
19
|
+
html_lines do |line|
|
20
|
+
conditions(tag, line, options[:if]) do
|
21
|
+
line = match(tag, line, :open) { |rest| "<#{wrapper.to_s + attributes(options)}>" + rest }
|
22
|
+
line = match(tag, line, :close) { |rest| rest + "</#{wrapper}>" }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def replace(tag, new_tag, options={})
|
28
|
+
html_lines do |line|
|
29
|
+
conditions(tag, line, options[:if]) do
|
30
|
+
line = match(tag, line, :open) { |open_tag| "<#{new_tag.to_s + attributes(options)}>" }
|
31
|
+
line = match(tag, line, :close) { |closing_tag| "</#{new_tag}>" }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def match(tag, line, state)
|
39
|
+
Matcher.new(tag, line).find(state) { |match| yield match }
|
40
|
+
end
|
41
|
+
|
42
|
+
def conditions(tag, line, condition)
|
43
|
+
return yield if condition.nil?
|
44
|
+
if condition.respond_to?(:call) && condition.call(Matcher.new(tag, line))
|
45
|
+
yield
|
46
|
+
elsif condition.is_a?(Hash) && Matcher.new(tag, line).match_all?(condition)
|
47
|
+
yield
|
48
|
+
elsif condition == true
|
49
|
+
yield
|
50
|
+
else
|
51
|
+
line
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def html_lines(&block)
|
56
|
+
self.html = html.lines.map { |line| yield line }.join
|
57
|
+
end
|
58
|
+
|
59
|
+
def attributes(options)
|
60
|
+
options.fetch(:with, {}).map { |k, v| " #{k}=\"#{v}\"" }.join
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module ClientPages
|
2
|
+
module MarkdownContent
|
3
|
+
class Renderer
|
4
|
+
class << self
|
5
|
+
def render_content(file, options = {})
|
6
|
+
html = new(file, options).html
|
7
|
+
block_given? ? yield(ContentBuilder.new(html)) : html.strip
|
8
|
+
rescue OpenURI::HTTPError
|
9
|
+
"404: could not find '#{file}'"
|
10
|
+
rescue Errno::ENOENT
|
11
|
+
"No such file or directory - #{file}"
|
12
|
+
rescue SocketError
|
13
|
+
'Error: content_path not available'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :file, :options
|
18
|
+
|
19
|
+
def initialize(file, options = {})
|
20
|
+
@file, @options = file, options
|
21
|
+
end
|
22
|
+
|
23
|
+
def html
|
24
|
+
html = html_from_markdown
|
25
|
+
html = template.call(ContentBuilder.new(html)) if options.key?(:template)
|
26
|
+
html
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def html_renderer
|
32
|
+
Redcarpet::Render::HTML.new(config.render_options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def extensions
|
36
|
+
config.markdown_extensions.merge(options.key?(:extensions) ? options[:extensions] : {})
|
37
|
+
end
|
38
|
+
|
39
|
+
def html_from_markdown
|
40
|
+
Redcarpet::Markdown.new(html_renderer, extensions).render(markdown)
|
41
|
+
end
|
42
|
+
|
43
|
+
def template
|
44
|
+
ClientPages.template[options[:template]]
|
45
|
+
end
|
46
|
+
|
47
|
+
def markdown
|
48
|
+
raw? ? file : read_file
|
49
|
+
end
|
50
|
+
|
51
|
+
def url
|
52
|
+
"#{content_path}/#{file}.md"
|
53
|
+
end
|
54
|
+
|
55
|
+
def read_file
|
56
|
+
if caching?
|
57
|
+
cache.fetch(url) { cache[url] = open(url).read }
|
58
|
+
else
|
59
|
+
open(url).read
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def content_path
|
64
|
+
config.remote ? config.remote_content_path : config.content_path
|
65
|
+
end
|
66
|
+
|
67
|
+
def raw?
|
68
|
+
config.raw_markdown || options[:raw]
|
69
|
+
end
|
70
|
+
|
71
|
+
def caching?
|
72
|
+
config.caching
|
73
|
+
end
|
74
|
+
|
75
|
+
def config
|
76
|
+
ClientPages.config
|
77
|
+
end
|
78
|
+
|
79
|
+
def cache
|
80
|
+
ClientPages.cache
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ClientPages
|
2
|
+
class Matcher
|
3
|
+
attr_accessor :tag, :line
|
4
|
+
|
5
|
+
def initialize(tag, line)
|
6
|
+
@tag, @line = tag, line
|
7
|
+
end
|
8
|
+
|
9
|
+
def match?(attribute, match)
|
10
|
+
!!line.match(/<#{tag}[^>]*#{attribute}="#{match}"/i)
|
11
|
+
end
|
12
|
+
|
13
|
+
def match_all?(attributes)
|
14
|
+
attributes.keys.all? { |key| match?(key, attributes[key]) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def match_any?(attribute, match)
|
18
|
+
!!line.match(/#{attribute}="#{match}"/i)
|
19
|
+
end
|
20
|
+
|
21
|
+
def includes?(pattern)
|
22
|
+
!!line.match(pattern)
|
23
|
+
end
|
24
|
+
|
25
|
+
def find(type)
|
26
|
+
if block_given? && includes?(tag_pattern[type])
|
27
|
+
line.gsub(tag_pattern[type]) { |match| yield match }
|
28
|
+
else
|
29
|
+
line
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def tag_pattern
|
36
|
+
{ open: /<#{tag}[^>]*>/, close: /<\/#{tag}[^>]*>/ }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/client_pages/version.rb
CHANGED
data/lib/client_pages.rb
CHANGED
@@ -4,6 +4,15 @@ require 'open-uri'
|
|
4
4
|
require 'redcarpet'
|
5
5
|
|
6
6
|
module ClientPages
|
7
|
+
autoload :Matcher, 'client_pages/matcher'
|
8
|
+
autoload :Template, 'client_pages/template'
|
9
|
+
autoload :Configuration, 'client_pages/configuration'
|
10
|
+
|
11
|
+
module MarkdownContent
|
12
|
+
autoload :ContentBuilder, 'client_pages/markdown_content/content_builder'
|
13
|
+
autoload :Renderer, 'client_pages/markdown_content/renderer'
|
14
|
+
end
|
15
|
+
|
7
16
|
class << self
|
8
17
|
attr_accessor :configuration
|
9
18
|
|
@@ -12,207 +21,16 @@ module ClientPages
|
|
12
21
|
block_given? ? yield(configuration) : configuration
|
13
22
|
end
|
14
23
|
|
15
|
-
def
|
16
|
-
@
|
17
|
-
end
|
18
|
-
|
19
|
-
def clear_cache(key=nil)
|
20
|
-
if key
|
21
|
-
cache.delete(key)
|
22
|
-
"cache cleared: #{key}"
|
23
|
-
else
|
24
|
-
cache.clear
|
25
|
-
'cache cleared'
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
module MarkdownContent
|
31
|
-
class MarkdownContentRenderer
|
32
|
-
include ClientPages::MarkdownContent
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.render_content(file, options={})
|
36
|
-
MarkdownContentRenderer.new.render_content(file, options)
|
37
|
-
end
|
38
|
-
|
39
|
-
class Matcher
|
40
|
-
attr_accessor :tag, :line
|
41
|
-
|
42
|
-
def initialize(tag, line)
|
43
|
-
@tag, @line = tag, line
|
44
|
-
end
|
45
|
-
|
46
|
-
def exact_match?(attribute, match)
|
47
|
-
!!line.match(/<#{tag}[^>]*#{attribute}="#{match}"/i)
|
48
|
-
end
|
49
|
-
|
50
|
-
def attr?(attribute, match)
|
51
|
-
!!line.match(/#{attribute}="#{match}"/i)
|
52
|
-
end
|
53
|
-
|
54
|
-
def match?(pattern)
|
55
|
-
!!line.match(pattern)
|
56
|
-
end
|
57
|
-
|
58
|
-
def find(type)
|
59
|
-
pattern = { opening: /<#{tag}[^>]*>/, closing: /<\/#{tag}[^>]*>/ }[type]
|
60
|
-
if block_given? && !!line.match(pattern)
|
61
|
-
line.gsub(pattern) { |match| yield match }
|
62
|
-
else
|
63
|
-
line
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
class ContentBuilder
|
69
|
-
attr_accessor :html
|
70
|
-
|
71
|
-
def initialize(html)
|
72
|
-
@html = html
|
73
|
-
end
|
74
|
-
|
75
|
-
def modify(tag, options={}, conditions=true)
|
76
|
-
if conditions.respond_to? :call
|
77
|
-
html_lines do |line|
|
78
|
-
if conditions.call(Matcher.new(tag, line))
|
79
|
-
set_options_for_tags_per_line(options, tag, line)
|
80
|
-
else
|
81
|
-
line
|
82
|
-
end
|
83
|
-
end
|
84
|
-
elsif conditions.is_a?(Hash)
|
85
|
-
html_lines do |line|
|
86
|
-
if conditions.keys.all? { |key| Matcher.new(tag, line).exact_match?(key, conditions[key]) }
|
87
|
-
set_options_for_tags_per_line(options, tag, line)
|
88
|
-
else
|
89
|
-
line
|
90
|
-
end
|
91
|
-
end
|
92
|
-
elsif !!conditions
|
93
|
-
set_options_for_tags(options, tag)
|
94
|
-
end
|
95
|
-
self.html
|
96
|
-
end
|
97
|
-
|
98
|
-
def wrap(tag, options={})
|
99
|
-
html_lines do |line|
|
100
|
-
line = Matcher.new(tag, line).find(:opening) do |match|
|
101
|
-
"<#{options[:wrapper]} class=\"#{options[:class]}\">#{match}"
|
102
|
-
end
|
103
|
-
line = Matcher.new(tag, line).find(:closing) do |match|
|
104
|
-
"#{match}</#{options[:wrapper]}>"
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def replace(tag, new_tag, options={})
|
110
|
-
html_lines do |line|
|
111
|
-
line = Matcher.new(tag, line).find(:opening) do |match|
|
112
|
-
"<#{new_tag} class=\"#{options[:class]}\">"
|
113
|
-
end
|
114
|
-
line = Matcher.new(tag, line).find(:closing) do |match|
|
115
|
-
"</#{new_tag}>"
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end # ContentBuilder
|
119
|
-
|
120
|
-
private
|
121
|
-
|
122
|
-
def html_lines(&block)
|
123
|
-
self.html = html.lines.map { |line| yield line }.join
|
124
|
-
end
|
125
|
-
|
126
|
-
def set_options_for_tags(options, tag)
|
127
|
-
html_lines { |line| set_options_for_tags_per_line(options, tag, line) }
|
128
|
-
end
|
129
|
-
|
130
|
-
def set_options_for_tags_per_line(options, tag, line)
|
131
|
-
options.each { |k, v| line = line.gsub(/<#{tag}/, "<#{tag} #{k}=\"#{v}\"") }
|
132
|
-
line
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def render_content(file, options = markdown_extensions)
|
137
|
-
html = Redcarpet::Markdown.new(html_renderer, options).render(markdown(file))
|
138
|
-
if block_given?
|
139
|
-
yield(ContentBuilder.new(html))
|
140
|
-
else
|
141
|
-
html.strip
|
142
|
-
end
|
143
|
-
rescue OpenURI::HTTPError
|
144
|
-
"404: could not find '#{file}'"
|
145
|
-
rescue Errno::ENOENT => e
|
146
|
-
e.message
|
147
|
-
rescue SocketError
|
148
|
-
'Error: content_path not available'
|
24
|
+
def template
|
25
|
+
@template ||= {}
|
149
26
|
end
|
150
27
|
|
151
|
-
|
152
|
-
|
153
|
-
def html_renderer
|
154
|
-
Redcarpet::Render::HTML.new(config.render_options)
|
155
|
-
end
|
156
|
-
|
157
|
-
def markdown_extensions
|
158
|
-
config.markdown_extensions
|
159
|
-
end
|
160
|
-
|
161
|
-
def markdown(file)
|
162
|
-
url = "#{content_path}/#{file}.md"
|
163
|
-
if caching?
|
164
|
-
cache.fetch(url) { cache[url] = open(url).read }
|
165
|
-
else
|
166
|
-
open(url).read
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
def config
|
171
|
-
ClientPages.config
|
28
|
+
def templates(&block)
|
29
|
+
yield Template.new
|
172
30
|
end
|
173
31
|
|
174
32
|
def cache
|
175
|
-
|
176
|
-
end
|
177
|
-
|
178
|
-
def caching?
|
179
|
-
config.caching
|
180
|
-
end
|
181
|
-
|
182
|
-
def remote?
|
183
|
-
config.remote
|
184
|
-
end
|
185
|
-
|
186
|
-
def content_path
|
187
|
-
remote? ? config.remote_content_path : config.content_path
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
class Configuration
|
192
|
-
attr_accessor :content_path, :remote, :remote_content_path, :caching, :fallback, :i18n
|
193
|
-
attr_reader :render_options, :markdown_extensions
|
194
|
-
|
195
|
-
def initialize
|
196
|
-
@content_path = 'content'
|
197
|
-
@render_options = {}
|
198
|
-
@markdown_extensions = {}
|
199
|
-
end
|
200
|
-
|
201
|
-
def render_options=(options)
|
202
|
-
@render_options.merge!(options)
|
203
|
-
end
|
204
|
-
|
205
|
-
def markdown_extensions=(options)
|
206
|
-
@markdown_extensions.merge!(options)
|
207
|
-
end
|
208
|
-
|
209
|
-
def to_hash
|
210
|
-
# TODO: instance vars get
|
211
|
-
{
|
212
|
-
content_path: content_path,
|
213
|
-
render_options: render_options,
|
214
|
-
markdown_extensions: markdown_extensions
|
215
|
-
}
|
33
|
+
@cache ||= {}
|
216
34
|
end
|
217
35
|
end
|
218
36
|
end
|
File without changes
|
File without changes
|
File without changes
|