client_pages 0.0.2.alpha → 0.0.3.beta

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
  SHA1:
3
- metadata.gz: 82904ac8341a7933e443e28906539c0e6f70e4da
4
- data.tar.gz: 3d68be7fa246b1de11e4fee95750293e8bc0dfc8
3
+ metadata.gz: 651585c4dbeab42b84039c22aec54878b9f54426
4
+ data.tar.gz: df24efef446ba402721bf025295c0d978103dfd4
5
5
  SHA512:
6
- metadata.gz: c273aa8f22b87c4b49e91f69127955ebaa0f85bd5f00989ddb0e2df70e1b3a61222887e501da64174d0986f34aff7fbe2226a8860ceb28012843fb9f7e94c178
7
- data.tar.gz: c9d878fa73bf1b6962d50edfbda5c34092c6cdb806e67af0f9ec1ab25dedced2319f0831755de10cacca9020bf67b6dfe6e6fd81afffd2ad6c1f79d588273415
6
+ metadata.gz: 4f859d580c6ba704bec2fd9dcbb05baa4208bae91c355c6c8618f55d9a46ce32bceeaa0b4bab8622ca4b2279dcd7a6d577908a33bfc664e39e4b391b122071d6
7
+ data.tar.gz: 9812ecd03067ce9907d6fe3d0c1fd58d6625877fb1f2d44a67af5ec5535e373187abc1aa4313cb82db0184968cf472ffa59c32d0d4b14a459988942aecad49f2
data/.gitignore CHANGED
@@ -17,4 +17,4 @@ test/tmp
17
17
  test/version_tmp
18
18
  tmp
19
19
  .rvmrc
20
- .rubocop.yml
20
+ *.notes
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
- # Ideas/Notes:
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
- **Ever heard "can we change the text on page x?"**
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 this.
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 either complete or by passing a file_path (which is the cache key):
172
-
173
- you can accomplish this with some additional code.
143
+ you can flush the cache also at runtime with
174
144
 
175
- ```code follows```
145
+ ```cache.clear```
176
146
 
177
- or run the corresponding command. (not implemented yet)
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: :spec
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
@@ -0,0 +1,7 @@
1
+ module ClientPages
2
+ class Template
3
+ def set(name, &settings)
4
+ ClientPages.template[name] = Proc.new(&settings)
5
+ end
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module ClientPages
2
- VERSION = '0.0.2.alpha'
2
+ VERSION = '0.0.3.beta'
3
3
  end
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 cache
16
- @cache ||= {}
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
- private
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
- ClientPages.cache
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
@@ -0,0 +1,3 @@
1
+ # foo
2
+
3
+ bar