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
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
# Snippr
|
2
|
+
## File based content management
|
3
|
+
|
4
|
+
A snippr file is a piece of HTML or raw text to be included in a website. They are plain text
|
5
|
+
files stored on the file system. Snippr files end with ".snip" and are read from the Snippr path.
|
6
|
+
|
7
|
+
## Snippr path
|
8
|
+
|
9
|
+
You need to specify the path to the directory where your Snippr files are stored:
|
10
|
+
|
11
|
+
Snippr.path = File.join File.dirname(__FILE__), "..", "snippr"
|
12
|
+
|
13
|
+
When running on JRuby, you can also set the path via JVM properties. The property you need to
|
14
|
+
specify is defined in Snippr::Path::JVMProperty. This allows system administrators to change the
|
15
|
+
path without having to touch your application.
|
16
|
+
|
17
|
+
## Loading a snippr
|
18
|
+
|
19
|
+
To load a snippr file, you can use the +load+ method, passing in the path to the snippr file as
|
20
|
+
a String (including path separators):
|
21
|
+
|
22
|
+
Snippr.load "tariff/einheit"
|
23
|
+
|
24
|
+
or by using multiple Strings or Symbols:
|
25
|
+
|
26
|
+
Snippr.load :tariff, :einheit
|
27
|
+
|
28
|
+
### Dynamic values
|
29
|
+
|
30
|
+
A snippr file may contain placeholders to be replaced with dynamic values. Placeholders are
|
31
|
+
wrapped in curly braces.
|
32
|
+
|
33
|
+
<p>You're topup of {topup_amount} at {date_today} was successful.</p>
|
34
|
+
|
35
|
+
To replace both {topup_amount} and {date_today} with a dynamic value, you just pass in a Hash of
|
36
|
+
placeholders and dynamic values when loading a snippr file.
|
37
|
+
|
38
|
+
Snippr.load :topup, :success, :topup_amount => number_to_currency(15), :date_today => Date.today
|
39
|
+
|
40
|
+
The result will obviously be something like:
|
41
|
+
|
42
|
+
<p>You're topup of 15,00 € at 2010-04-03 was successful.</p>
|
43
|
+
|
44
|
+
### calling methods on passed variables
|
45
|
+
|
46
|
+
You can call methods on passed parameters. Calling this:
|
47
|
+
|
48
|
+
class Klazz
|
49
|
+
def doit; "HELLO"; end
|
50
|
+
end
|
51
|
+
Snippr.load :snip :a_variable => Klass.new
|
52
|
+
|
53
|
+
on ...
|
54
|
+
|
55
|
+
<p>Snippr says: {a_variable.doit}</p>
|
56
|
+
|
57
|
+
will yield:
|
58
|
+
|
59
|
+
<p>Snippr says: HELLO</p>
|
60
|
+
|
61
|
+
You can even pass parameters to the call. Those *must* be enclosed in quotes ("):
|
62
|
+
|
63
|
+
class Klazz
|
64
|
+
def doitagain(p); "HELLO #{p}"; end
|
65
|
+
end
|
66
|
+
Snippr.load :snip :a_variable => Klass.new
|
67
|
+
|
68
|
+
on ...
|
69
|
+
|
70
|
+
<p>Snippr says: {a_variable.doitagain("SNIPPR")}</p>
|
71
|
+
|
72
|
+
will yield:
|
73
|
+
|
74
|
+
<p>Snippr says: HELLO SNIPPR</p>
|
75
|
+
|
76
|
+
### Meta Infos
|
77
|
+
|
78
|
+
A snippet can not only hold content but also meta infos for this snippet.
|
79
|
+
|
80
|
+
Inspired by [jekyll](http://jekyllrb.com) a snippet can host metdata that are accessable via the `.meta` method on a loaded snippet.
|
81
|
+
`.meta' will return an empty hash when no data was found.
|
82
|
+
|
83
|
+
Metadata must be placed at the top of the snippet and is delimited with three dashed.
|
84
|
+
The data itself is parsed as YAML:
|
85
|
+
|
86
|
+
---
|
87
|
+
a_yaml: hash
|
88
|
+
---
|
89
|
+
normal snippet content comes here until the end of the file
|
90
|
+
|
91
|
+
### Including snippr files inside other files
|
92
|
+
|
93
|
+
A snippr file can include another snippr file:
|
94
|
+
|
95
|
+
This snippr file includes another {snip:filepath/of/snip} file
|
96
|
+
|
97
|
+
This will cause `filepath/of/snip.snip` to be included in place.
|
98
|
+
|
99
|
+
Dynamic values of the parent snip will be accessable inside the included snip file.
|
100
|
+
|
101
|
+
You can pass additional dynamic values when using `{snip}`. These will override any parent parameter.
|
102
|
+
|
103
|
+
{snip:filepath/of/snip,dyn_key1=dyn_value,dyn_key2=dyn_value2}
|
104
|
+
|
105
|
+
Those will be available as {dyn_key1} and {dyn_key2} in filepath/of/snip.snip
|
106
|
+
|
107
|
+
## I18n
|
108
|
+
|
109
|
+
Snippr comes with support for I18n, but up until further notice, you have to manually enable this
|
110
|
+
behavior in your application.
|
111
|
+
|
112
|
+
Snippr.i18n = true
|
113
|
+
|
114
|
+
Afterwards Snippr uses the locale specified via I18n and automatically prepends the current locale
|
115
|
+
prefixed with a "_" to your snippr files.
|
116
|
+
|
117
|
+
I18n.locale = :de
|
118
|
+
Snippr.load :shop # tries to load "shop_de.snip" relative to your Snippr path
|
119
|
+
|
120
|
+
I18n.locale = :en
|
121
|
+
Snippr.load :shop # tries to load "shop_en.snip" relative to your Snippr path
|
122
|
+
|
123
|
+
## Wiki Syntax
|
124
|
+
|
125
|
+
Until now, only wiki links with text are supported by Snippr:
|
126
|
+
|
127
|
+
[[http://www.blaulabs.de|blaulabs]]
|
128
|
+
|
129
|
+
will be converted to:
|
130
|
+
|
131
|
+
<a href="http://www.blaulabs.de">blaulabs</a>
|
132
|
+
|
133
|
+
## Rails Helper
|
134
|
+
|
135
|
+
When using the Snippr module with Rails, it automatically adds the +Snippr::Helper+ module to
|
136
|
+
your views. You can then use the +snippr+ helper method to load snippr files.
|
137
|
+
|
138
|
+
%h1 Topup successful
|
139
|
+
.topup.info
|
140
|
+
= snippr :topup, :success
|
141
|
+
|
142
|
+
## Build Status
|
143
|
+
![Travis-CI](https://secure.travis-ci.org/blaulabs/snippr.png)
|
data/Rakefile
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
require "rubygems"
|
1
2
|
require "rake"
|
2
|
-
require "spec/rake/spectask"
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'ci/reporter/rake/rspec'
|
6
|
+
RSpec::Core::RakeTask.new :spec
|
7
|
+
task :default => %w(ci:setup:rspec spec)
|
7
8
|
|
8
9
|
begin
|
9
10
|
require "hanna/rdoctask"
|
data/lib/snippr.rb
CHANGED
@@ -1,2 +1,14 @@
|
|
1
|
-
require
|
2
|
-
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
|
3
|
+
Dir[File.expand_path '../snippr/*.rb', __FILE__].each {|f| require f}
|
4
|
+
Dir[File.expand_path '../snippr/normalizer/*.rb', __FILE__].each {|f| require f}
|
5
|
+
Dir[File.expand_path '../snippr/processor/*.rb', __FILE__].each {|f| require f}
|
6
|
+
|
7
|
+
Snippr::Normalizer.normalizers << Snippr::Normalizer::Camelizer.new
|
8
|
+
# don't use DeRester this for all apps, but configure it as needed
|
9
|
+
# Snippr::Normalizer.normalizers << Snippr::Normalizer::DeRester.new
|
10
|
+
|
11
|
+
Snippr::Processor.processors << Snippr::Processor::Functions.new
|
12
|
+
Snippr::Processor.processors << Snippr::Processor::Dynamics.new
|
13
|
+
Snippr::Processor.processors << Snippr::Processor::Links.new
|
14
|
+
Snippr::Processor.processors << Snippr::Processor::Wikilinks.new
|
data/lib/snippr/i18n.rb
CHANGED
@@ -2,25 +2,24 @@ require "i18n"
|
|
2
2
|
|
3
3
|
# = Snippr::I18n
|
4
4
|
#
|
5
|
-
#
|
5
|
+
# Provides support for I18n snippr files.
|
6
6
|
module Snippr
|
7
7
|
module I18n
|
8
8
|
|
9
|
-
#
|
10
|
-
def
|
11
|
-
|
9
|
+
# Returns whether to use I18n snippr files.
|
10
|
+
def self.enabled?
|
11
|
+
!!@@enabled
|
12
12
|
end
|
13
13
|
|
14
|
-
#
|
15
|
-
def
|
16
|
-
|
14
|
+
# Sets whether to use I18n snippr files.
|
15
|
+
def self.enabled=(enabled)
|
16
|
+
@@enabled = enabled
|
17
17
|
end
|
18
18
|
|
19
19
|
# Returns the current locale prefixed with a "_" from I18n if I18n is enabled.
|
20
20
|
# Otherwise defaults to an empty String.
|
21
|
-
def locale
|
22
|
-
|
23
|
-
["_", ::I18n.locale].join
|
21
|
+
def self.locale(enabled=nil)
|
22
|
+
(enabled.nil? ? enabled? : enabled) ? "_#{::I18n.locale}" : ''
|
24
23
|
end
|
25
24
|
|
26
25
|
end
|
data/lib/snippr/links.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# = Snippr::LinkHelper
|
2
|
+
#
|
3
|
+
# This module can be included to get functionality to adjust links.
|
4
|
+
module Snippr
|
5
|
+
module Links
|
6
|
+
|
7
|
+
HREF_REGEX = /(href *= *['"])([^'"]*)(['"])/i
|
8
|
+
|
9
|
+
# Returns the regular expressions used to determine which urls to exclude from adjustment.
|
10
|
+
def self.adjust_urls_except
|
11
|
+
@@adjust_urls_except ||= [/^#/, /^[a-z]+:/i]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Sets the regular expressions used to determine which urls to exclude from adjustment.
|
15
|
+
def self.adjust_urls_except=(adjust_urls_except)
|
16
|
+
@@adjust_urls_except = adjust_urls_except
|
17
|
+
end
|
18
|
+
|
19
|
+
# Adjusts a complete anchor tag, allowing the custom protocol popup: which will be converted to a javascript call to popup(this).
|
20
|
+
def self.adjust_link(link)
|
21
|
+
return link if link !~ HREF_REGEX
|
22
|
+
url = $2
|
23
|
+
if url =~ /popup:\/*(.*)$/i
|
24
|
+
url = adjust_url $1
|
25
|
+
onclick = "onclick=\"if (typeof popup == 'undefined') { return true; } else { popup(this); return false; }\""
|
26
|
+
# replace an existing onclick (if present)
|
27
|
+
link_with_onclick = link.gsub /onclick *= *['"][^'"]*['"]/i, onclick
|
28
|
+
# add a new onclick (when there was no existing onclick)
|
29
|
+
link_with_onclick = link.gsub /(^[^>]+)>/, "\\1 #{onclick}>" if link_with_onclick == link
|
30
|
+
link = link_with_onclick
|
31
|
+
else
|
32
|
+
url = adjust_url url
|
33
|
+
end
|
34
|
+
link.gsub HREF_REGEX, "\\1#{url}\\3"
|
35
|
+
end
|
36
|
+
|
37
|
+
# Adjusts an url, prepending / and relative url root (context path) as needed.
|
38
|
+
def self.adjust_url(url)
|
39
|
+
adjust_urls_except.each do |regex|
|
40
|
+
return url if url =~ regex
|
41
|
+
end
|
42
|
+
root = relative_url_root
|
43
|
+
url.gsub(/^(#{root}|\/)?/, root)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the relative url root (context path) the application is deployed to.
|
47
|
+
def self.relative_url_root
|
48
|
+
if defined? ActionController::Base
|
49
|
+
root = ActionController::Base.config.relative_url_root || '/'
|
50
|
+
root = "/#{root}" unless root.start_with?('/')
|
51
|
+
root << '/' unless root.end_with?('/')
|
52
|
+
root
|
53
|
+
else
|
54
|
+
'/'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require "yaml"
|
3
|
+
|
4
|
+
# = Snippr::MetaData
|
5
|
+
#
|
6
|
+
# Handles Snippr's YAML Front Matter inspired by Jekyll.
|
7
|
+
# Useful for passing meta information about a Snip to the app.
|
8
|
+
module Snippr
|
9
|
+
|
10
|
+
class MetaData
|
11
|
+
|
12
|
+
def self.extract(name, content)
|
13
|
+
if content =~ /^(---\s*\n.*?\n?)^(---\s*$?)/m
|
14
|
+
content = Regexp.last_match.post_match.strip
|
15
|
+
meta = yaml_load(name, $1)
|
16
|
+
end
|
17
|
+
|
18
|
+
meta = meta ? meta : {}
|
19
|
+
[content, meta]
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def self.yaml_load(name, yml)
|
25
|
+
YAML.load(yml)
|
26
|
+
rescue Exception => e
|
27
|
+
Snippr.logger.warn "Unable to extract meta data from Snip #{name.inspect}: #{e.message}"
|
28
|
+
{}
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# = Snippr::Normalizer
|
2
|
+
#
|
3
|
+
# Provides methods to normalize snippr path elements.
|
4
|
+
module Snippr
|
5
|
+
module Normalizer
|
6
|
+
|
7
|
+
# Returns a (modifiable) list of normalizers that'll be used to normalize a path element.
|
8
|
+
def self.normalizers
|
9
|
+
@normalizers ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
# Sends the given path element to all the configured normalizers and returns the result.
|
13
|
+
def self.normalize(path_element)
|
14
|
+
@normalizers.inject(path_element) {|e, normalizer| normalizer.normalize e}
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# = Snippr::Normalizer::Camelizer
|
2
|
+
#
|
3
|
+
# When given a symbol, normalizes it to a lower camelized string, otherwise just returns the given string.
|
4
|
+
module Snippr
|
5
|
+
|
6
|
+
module Normalizer
|
7
|
+
|
8
|
+
class Camelizer
|
9
|
+
|
10
|
+
def normalize(path_element)
|
11
|
+
path_element.kind_of?(Symbol) ? path_element.to_s.camelize(:lower) : path_element
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# = Snippr::Normalizer::DeRester
|
2
|
+
#
|
3
|
+
# "Redirects" REST path elements that are accessed via POST (create, update destroy) with
|
4
|
+
# their corresponding GET elements (new, edit, show) so that when eg create is rendered due
|
5
|
+
# to an error in the action, it just looks exactly like the new page it was issued from.
|
6
|
+
module Snippr
|
7
|
+
|
8
|
+
module Normalizer
|
9
|
+
|
10
|
+
class DeRester
|
11
|
+
|
12
|
+
def normalize(path_element)
|
13
|
+
case path_element.to_s
|
14
|
+
when "create" then "new"
|
15
|
+
when "update" then "edit"
|
16
|
+
when "destroy" then "show"
|
17
|
+
else path_element.to_s
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/lib/snippr/path.rb
CHANGED
@@ -1,25 +1,46 @@
|
|
1
1
|
# = Snippr::Path
|
2
2
|
#
|
3
|
-
#
|
3
|
+
# Provides methods for dealing with the path to snippr files.
|
4
4
|
module Snippr
|
5
5
|
module Path
|
6
6
|
|
7
7
|
# The JVM property to set the path to the snippr files.
|
8
|
-
|
8
|
+
JVM_PROPERTY = 'cms.snippet.path'
|
9
9
|
|
10
10
|
# Returns the path to the snippr files (from JVM properties if available).
|
11
|
-
def path
|
12
|
-
|
11
|
+
def self.path
|
12
|
+
@@path ||= JavaLang::System.get_property(JVM_PROPERTY) rescue ""
|
13
13
|
end
|
14
14
|
|
15
15
|
# Sets the path to the snippr files.
|
16
|
-
def path=(path)
|
17
|
-
|
16
|
+
def self.path=(path)
|
17
|
+
@@path = path.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
# Builds a snippr name from an array of path parts.
|
21
|
+
def self.normalize_name(*names)
|
22
|
+
names.map do |name|
|
23
|
+
Normalizer.normalize(name)
|
24
|
+
end.join("/")
|
25
|
+
end
|
26
|
+
|
27
|
+
# Builds a snippr path (inside the configured path) from a name and an optional extension.
|
28
|
+
def self.path_from_name(name, ext = nil)
|
29
|
+
File.join(path, (ext ? "#{name}.#{ext}" : name))
|
30
|
+
end
|
31
|
+
|
32
|
+
# Lists all snips inside a snippr directory specified by path parts.
|
33
|
+
def self.list(*names)
|
34
|
+
dir = path_from_name normalize_name *names
|
35
|
+
Dir["#{dir}/*#{I18n.locale}.#{Snip::FILE_EXTENSION}"].map do |snip|
|
36
|
+
snip.gsub(/^.*\/([^\.]+)?\.#{Snip::FILE_EXTENSION}$/, '\1').gsub(/_.*$/, '').underscore
|
37
|
+
end.sort.map(&:to_sym)
|
18
38
|
end
|
19
39
|
|
20
40
|
private
|
21
41
|
|
22
42
|
if RUBY_PLATFORM =~ /java/
|
43
|
+
require 'java'
|
23
44
|
module JavaLang
|
24
45
|
include_package "java.lang"
|
25
46
|
end
|