snippr 0.3.0 → 0.13.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/README.md +143 -0
- data/Rakefile +5 -4
- data/lib/snippr.rb +14 -2
- data/lib/snippr/i18n.rb +9 -10
- data/lib/snippr/links.rb +59 -0
- data/lib/snippr/meta_data.rb +33 -0
- data/lib/snippr/normalizer.rb +18 -0
- data/lib/snippr/normalizer/camelizer.rb +18 -0
- data/lib/snippr/normalizer/de_rester.rb +25 -0
- data/lib/snippr/path.rb +27 -6
- data/lib/snippr/processor.rb +18 -0
- data/lib/snippr/processor/dynamics.rb +31 -0
- data/lib/snippr/processor/functions.rb +50 -0
- data/lib/snippr/processor/links.rb +20 -0
- data/lib/snippr/processor/wikilinks.rb +20 -0
- data/lib/snippr/snip.rb +57 -0
- data/lib/snippr/snippr.rb +41 -45
- data/lib/snippr/view_helper.rb +71 -0
- data/snippr.gemspec +30 -0
- data/spec/fixtures/a/path/aSnippet.snip +1 -0
- data/spec/fixtures/a/path/aSnippetWithParam.snip +1 -0
- data/spec/fixtures/controller/action/aSnippet.snip +1 -0
- data/spec/fixtures/empty.snip +3 -0
- data/spec/fixtures/i18n/list_de.snip +0 -0
- data/spec/fixtures/meta/broken.snip +5 -0
- data/spec/fixtures/meta/withContent.snip +5 -0
- data/spec/fixtures/meta/withContentNoNewline.snip +4 -0
- data/spec/fixtures/meta/withNoContent.snip +4 -0
- data/spec/fixtures/withUnderscore/andUnderscore/aSnippet.snip +1 -0
- data/spec/fixtures/withViewHelperMethod.snip +1 -0
- data/spec/snippr/i18n_spec.rb +30 -0
- data/spec/snippr/links_spec.rb +137 -0
- data/spec/snippr/normalizer/camelizer_spec.rb +13 -0
- data/spec/snippr/normalizer/de_rester_spec.rb +24 -0
- data/spec/snippr/normalizer_spec.rb +40 -0
- data/spec/snippr/path_spec.rb +87 -0
- data/spec/snippr/processor/dynamics_spec.rb +49 -0
- data/spec/snippr/processor/functions_spec.rb +72 -0
- data/spec/snippr/processor/links_spec.rb +12 -0
- data/spec/snippr/processor/wikilinks_spec.rb +12 -0
- data/spec/snippr/processor_spec.rb +35 -0
- data/spec/snippr/snip_spec.rb +179 -0
- data/spec/snippr/snippr_spec.rb +60 -55
- data/spec/snippr/view_helper_spec.rb +221 -0
- data/spec/spec_helper.rb +17 -3
- metadata +178 -87
- data/README.rdoc +0 -77
- data/lib/snippr/core_ext.rb +0 -12
- data/lib/snippr/helper.rb +0 -23
- data/lib/snippr/link.rb +0 -26
- data/spec/fixtures/tariff/einheit.snip +0 -1
- data/spec/fixtures/wiki.snip +0 -1
- data/spec/snippr/core_ext_spec.rb +0 -11
@@ -0,0 +1,18 @@
|
|
1
|
+
# = Snippr::Processor
|
2
|
+
#
|
3
|
+
# Provides methods to process snippr content.
|
4
|
+
module Snippr
|
5
|
+
module Processor
|
6
|
+
|
7
|
+
# Returns a (modifiable) list of processors that'll be used to process the content.
|
8
|
+
def self.processors
|
9
|
+
@processors ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
# Sends the given content and opts to all the configured processors and returns the result.
|
13
|
+
def self.process(content, opts)
|
14
|
+
@processors.inject(content) {|c, processor| processor.process c, opts}
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# = Snippr::Processor::Dynamics
|
2
|
+
#
|
3
|
+
# Replaces {placeholder} placeholders in the content with values taken from the given opts.
|
4
|
+
module Snippr
|
5
|
+
|
6
|
+
module Processor
|
7
|
+
|
8
|
+
class Dynamics
|
9
|
+
|
10
|
+
def process(content, opts = {})
|
11
|
+
opts.inject(content) do |c, pv|
|
12
|
+
placeholder, value = pv
|
13
|
+
c.gsub(/\{#{placeholder}(?:\.(.*?)\(["]?(.*?)["]?\))?\}/m) do |match|
|
14
|
+
if $1 && value.respond_to?($1)
|
15
|
+
method = $1
|
16
|
+
params = ($2 || "").gsub(/[\t\r\n]/,"").split("\",\"")
|
17
|
+
value.send(method, *params).to_s
|
18
|
+
elsif $1
|
19
|
+
match
|
20
|
+
else
|
21
|
+
value.to_s
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# = Snippr::Processor::Functions
|
2
|
+
#
|
3
|
+
# Processes several functions in {command:options} syntax.
|
4
|
+
module Snippr
|
5
|
+
|
6
|
+
module Processor
|
7
|
+
|
8
|
+
class Functions
|
9
|
+
|
10
|
+
def process(content, opts = {})
|
11
|
+
content.scan(/\{(.*?):(.*?)\}/) do |match|
|
12
|
+
command, func_options = match
|
13
|
+
options = opts.merge(hashify(func_options))
|
14
|
+
command = "cmd_#{command}"
|
15
|
+
content = send(command, content, options, func_options) if respond_to?(command, true)
|
16
|
+
end
|
17
|
+
content
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# expand another snip
|
23
|
+
# {snip:path/to/snippet}
|
24
|
+
def cmd_snip(unprocessed_content, opts, original_options)
|
25
|
+
path = opts[:default].split("/")
|
26
|
+
snip_content = Snippr::Snip.new(*path + [opts]).content
|
27
|
+
unprocessed_content.gsub("{snip:#{original_options}}", snip_content)
|
28
|
+
end
|
29
|
+
|
30
|
+
# home
|
31
|
+
# snip=home
|
32
|
+
# snip=home,var=1
|
33
|
+
def hashify(func_options="")
|
34
|
+
options = {}
|
35
|
+
func_options.split(",").each do |option|
|
36
|
+
opt_key, opt_value = option.split("=")
|
37
|
+
unless opt_value
|
38
|
+
opt_value = opt_key
|
39
|
+
opt_key = :default
|
40
|
+
end
|
41
|
+
options[opt_key.to_sym] = opt_value
|
42
|
+
end
|
43
|
+
options
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# = Snippr::Processor::Links
|
2
|
+
#
|
3
|
+
# Adjusts URLs in links.
|
4
|
+
module Snippr
|
5
|
+
|
6
|
+
module Processor
|
7
|
+
|
8
|
+
class Links
|
9
|
+
|
10
|
+
def process(content, opts = {})
|
11
|
+
content.gsub /<a [^>]+>[^<]*<\/a>/i do |match|
|
12
|
+
Snippr::Links.adjust_link match
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# = Snippr::Processor::Wikilinks
|
2
|
+
#
|
3
|
+
# Replaces links in [url|title] syntax with real links.
|
4
|
+
module Snippr
|
5
|
+
|
6
|
+
module Processor
|
7
|
+
|
8
|
+
class Wikilinks
|
9
|
+
|
10
|
+
def process(content, opts = {})
|
11
|
+
content.gsub /\[\[([^|]+)\|([^\]]+)\]\]/ do |match|
|
12
|
+
Snippr::Links.adjust_link "<a href=\"#{$1}\">#{$2}</a>"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/lib/snippr/snip.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# # -*- encoding : utf-8 -*-
|
2
|
+
# = Snippr::Snip
|
3
|
+
#
|
4
|
+
# Represents a single snip and provides methods to read data.
|
5
|
+
module Snippr
|
6
|
+
class Snip
|
7
|
+
|
8
|
+
extend ActiveSupport::Memoizable
|
9
|
+
|
10
|
+
FILE_EXTENSION = 'snip'
|
11
|
+
|
12
|
+
def initialize(*names)
|
13
|
+
names = strip_empty_values(names)
|
14
|
+
@opts = names.last.kind_of?(Hash) ? names.pop : {}
|
15
|
+
@opts.symbolize_keys!
|
16
|
+
@name = "#{Path.normalize_name(*names)}#{ I18n.locale(@opts[:i18n]) }"
|
17
|
+
@path = Path.path_from_name @name, (@opts[:extension] || FILE_EXTENSION)
|
18
|
+
@unprocessed_content, @meta = MetaData.extract(names, raw_content)
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :name, :path, :opts, :unprocessed_content, :meta
|
22
|
+
|
23
|
+
# Returns the processed and decorated content.
|
24
|
+
def content
|
25
|
+
if missing?
|
26
|
+
"<!-- missing snippr: #{name} -->"
|
27
|
+
else
|
28
|
+
content = Processor.process unprocessed_content, opts
|
29
|
+
"<!-- starting snippr: #{name} -->\n#{content}\n<!-- closing snippr: #{name} -->"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
memoize :content
|
33
|
+
alias :to_s :content
|
34
|
+
|
35
|
+
def raw_content
|
36
|
+
missing? ? '' : File.read(@path).strip
|
37
|
+
end
|
38
|
+
memoize :raw_content
|
39
|
+
|
40
|
+
# Returns whether the snip is missing or not.
|
41
|
+
def missing?
|
42
|
+
!File.exist? @path
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns whether the snip is empty or not.
|
46
|
+
def empty?
|
47
|
+
unprocessed_content.blank?
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def strip_empty_values(names)
|
53
|
+
names - [nil, ""]
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
data/lib/snippr/snippr.rb
CHANGED
@@ -1,7 +1,4 @@
|
|
1
|
-
require "
|
2
|
-
require "snippr/path"
|
3
|
-
require "snippr/i18n"
|
4
|
-
require "snippr/link"
|
1
|
+
require "logger"
|
5
2
|
|
6
3
|
# = Snippr
|
7
4
|
# ==== File based content management
|
@@ -9,56 +6,55 @@ require "snippr/link"
|
|
9
6
|
# A snippr file is a piece of HTML or raw text to be included in a website. They are plain text
|
10
7
|
# files stored on the file system. Snippr files end with ".snip" and are read from the Snippr path.
|
11
8
|
module Snippr
|
12
|
-
extend
|
13
|
-
extend Snippr::I18n
|
14
|
-
extend Snippr::Link
|
9
|
+
extend self
|
15
10
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
# The comments wrapping a snippr.
|
22
|
-
SnipprComments = "<!-- starting snippr: %s -->\n%s\n<!-- closing snippr: %s -->"
|
11
|
+
# Returns the path to the snippr files (from JVM properties if available).
|
12
|
+
def path
|
13
|
+
Path.path
|
14
|
+
end
|
23
15
|
|
24
|
-
|
25
|
-
|
16
|
+
# Sets the path to the snippr files.
|
17
|
+
def path=(path)
|
18
|
+
Path.path = path
|
19
|
+
end
|
26
20
|
|
21
|
+
# Returns whether to use I18n snippr files.
|
22
|
+
def i18n?
|
23
|
+
I18n.enabled?
|
24
|
+
end
|
27
25
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
@name = name_from args
|
33
|
-
SnipprComments % [@name, content, @name]
|
34
|
-
end
|
26
|
+
# Sets whether to use I18n snippr files.
|
27
|
+
def i18n=(enabled)
|
28
|
+
I18n.enabled = enabled
|
29
|
+
end
|
35
30
|
|
36
|
-
|
31
|
+
# Returns the regular expressions used to determine which urls to exclude from adjustment.
|
32
|
+
def adjust_urls_except
|
33
|
+
Links.adjust_urls_except
|
34
|
+
end
|
37
35
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
36
|
+
# Sets the regular expressions used to determine which urls to exclude from adjustment.
|
37
|
+
def adjust_urls_except=(adjust_urls_except)
|
38
|
+
Links.adjust_urls_except = adjust_urls_except
|
39
|
+
end
|
42
40
|
|
43
|
-
|
44
|
-
|
45
|
-
def content
|
46
|
-
return MissingSnipprTag unless File.exist? file
|
47
|
-
|
48
|
-
content = File.read(file).strip
|
49
|
-
insert_dynamics content
|
50
|
-
linkify content
|
51
|
-
end
|
41
|
+
# Sets the logger to use.
|
42
|
+
attr_writer :logger
|
52
43
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
44
|
+
# Returns the logger. Uses the Rails logger when available or falls back to a custom logger.
|
45
|
+
def logger
|
46
|
+
@logger ||= defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
|
47
|
+
end
|
57
48
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
49
|
+
# Expects the name of a snippr file. Also accepts a Hash of placeholders
|
50
|
+
# to be replaced with dynamic values.
|
51
|
+
def load(*args)
|
52
|
+
Snip.new(*args)
|
53
|
+
end
|
62
54
|
|
55
|
+
# Lists all snips inside a snippr directory specified by path parts.
|
56
|
+
def list(*args)
|
57
|
+
Path.list *args
|
63
58
|
end
|
59
|
+
|
64
60
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# = Snippr::ViewHelper
|
2
|
+
#
|
3
|
+
# This module is automatically included into +ActionView::Base+ when using the Snippr
|
4
|
+
# component with Rails. It provides a +snippr+ helper method for loading snippr files.
|
5
|
+
#
|
6
|
+
# %h1 Topup successful
|
7
|
+
# .topup.info
|
8
|
+
# = snippr :topup, :success
|
9
|
+
# %h1 Conditional output
|
10
|
+
# - snippr :topup, :conditional_snippr do |snip|
|
11
|
+
# #cond= snip
|
12
|
+
module Snippr
|
13
|
+
module ViewHelper
|
14
|
+
|
15
|
+
# Returns a snippr specified via +args+.
|
16
|
+
def snippr(*args)
|
17
|
+
snip = Snip.new *add_view_to_snippr_args(args)
|
18
|
+
content = snip.content.html_safe
|
19
|
+
|
20
|
+
if block_given?
|
21
|
+
if snip.missing? || snip.blank?
|
22
|
+
concat content
|
23
|
+
elsif content.strip.present?
|
24
|
+
yield content
|
25
|
+
end
|
26
|
+
0
|
27
|
+
else
|
28
|
+
extend_snip_content(content, snip)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def snippr_with_path(*args, &block)
|
33
|
+
path = if controller_name == "pages"
|
34
|
+
params[:id].split('/')
|
35
|
+
else
|
36
|
+
[controller_name, params[:action]]
|
37
|
+
end.compact.map { |e| e.to_s.camelize(:lower).to_sym }
|
38
|
+
snippr(*(path + args), &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def add_view_to_snippr_args(args)
|
44
|
+
variables = args.last.kind_of?(Hash) ? args.pop : {}
|
45
|
+
variables[:view] = self
|
46
|
+
args << variables
|
47
|
+
args
|
48
|
+
end
|
49
|
+
|
50
|
+
def extend_snip_content(content, snip)
|
51
|
+
content.class_eval %(
|
52
|
+
def missing?
|
53
|
+
#{snip.missing?}
|
54
|
+
end
|
55
|
+
def exists?
|
56
|
+
#{!snip.missing?}
|
57
|
+
end
|
58
|
+
def meta(key = nil)
|
59
|
+
meta = #{snip.meta.inspect}
|
60
|
+
key ? meta[key] : meta
|
61
|
+
end
|
62
|
+
)
|
63
|
+
content
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
if defined? ActionView::Base
|
70
|
+
ActionView::Base.send :include, Snippr::ViewHelper
|
71
|
+
end
|
data/snippr.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.name = "snippr"
|
4
|
+
s.version = "0.13.1"
|
5
|
+
s.date = Time.now
|
6
|
+
s.platform = Gem::Platform::RUBY
|
7
|
+
s.authors = ["Daniel Harrington", "Thomas Jachmann"]
|
8
|
+
s.email = ["me@rubiii.com", "self@thomasjachmann.com"]
|
9
|
+
s.homepage = "http://github.com/blaulabs/snippr"
|
10
|
+
s.summary = %q{File based content management}
|
11
|
+
s.description = %q{This gem provides ways to access file based cms resources from a rails app.}
|
12
|
+
|
13
|
+
s.rubyforge_project = "snippr"
|
14
|
+
|
15
|
+
s.add_runtime_dependency "i18n"
|
16
|
+
s.add_runtime_dependency "activesupport"
|
17
|
+
|
18
|
+
s.add_development_dependency "ci_reporter", "~> 1.6.5"
|
19
|
+
s.add_development_dependency "rspec", "~> 2.6.0"
|
20
|
+
s.add_development_dependency "mocha", "0.9.12"
|
21
|
+
s.add_development_dependency "rake", "~> 0.9.0"
|
22
|
+
# pin down ZenTest so that autotest works without upgrading rubygems
|
23
|
+
# see http://stackoverflow.com/questions/6802610/autotest-problem [mw, 2011-08-10]
|
24
|
+
s.add_development_dependency "ZenTest", "4.5.0"
|
25
|
+
|
26
|
+
s.files = `git ls-files`.split("\n")
|
27
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
28
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
29
|
+
s.require_paths = ["lib"]
|
30
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
a snippet
|
@@ -0,0 +1 @@
|
|
1
|
+
a snippet with param {param}
|
@@ -0,0 +1 @@
|
|
1
|
+
SNIPPET
|
File without changes
|