snippr 0.3.0 → 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/.gitignore +13 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +4 -0
  5. data/README.md +143 -0
  6. data/Rakefile +5 -4
  7. data/lib/snippr.rb +14 -2
  8. data/lib/snippr/i18n.rb +9 -10
  9. data/lib/snippr/links.rb +59 -0
  10. data/lib/snippr/meta_data.rb +33 -0
  11. data/lib/snippr/normalizer.rb +18 -0
  12. data/lib/snippr/normalizer/camelizer.rb +18 -0
  13. data/lib/snippr/normalizer/de_rester.rb +25 -0
  14. data/lib/snippr/path.rb +27 -6
  15. data/lib/snippr/processor.rb +18 -0
  16. data/lib/snippr/processor/dynamics.rb +31 -0
  17. data/lib/snippr/processor/functions.rb +50 -0
  18. data/lib/snippr/processor/links.rb +20 -0
  19. data/lib/snippr/processor/wikilinks.rb +20 -0
  20. data/lib/snippr/snip.rb +57 -0
  21. data/lib/snippr/snippr.rb +41 -45
  22. data/lib/snippr/view_helper.rb +71 -0
  23. data/snippr.gemspec +30 -0
  24. data/spec/fixtures/a/path/aSnippet.snip +1 -0
  25. data/spec/fixtures/a/path/aSnippetWithParam.snip +1 -0
  26. data/spec/fixtures/controller/action/aSnippet.snip +1 -0
  27. data/spec/fixtures/empty.snip +3 -0
  28. data/spec/fixtures/i18n/list_de.snip +0 -0
  29. data/spec/fixtures/meta/broken.snip +5 -0
  30. data/spec/fixtures/meta/withContent.snip +5 -0
  31. data/spec/fixtures/meta/withContentNoNewline.snip +4 -0
  32. data/spec/fixtures/meta/withNoContent.snip +4 -0
  33. data/spec/fixtures/withUnderscore/andUnderscore/aSnippet.snip +1 -0
  34. data/spec/fixtures/withViewHelperMethod.snip +1 -0
  35. data/spec/snippr/i18n_spec.rb +30 -0
  36. data/spec/snippr/links_spec.rb +137 -0
  37. data/spec/snippr/normalizer/camelizer_spec.rb +13 -0
  38. data/spec/snippr/normalizer/de_rester_spec.rb +24 -0
  39. data/spec/snippr/normalizer_spec.rb +40 -0
  40. data/spec/snippr/path_spec.rb +87 -0
  41. data/spec/snippr/processor/dynamics_spec.rb +49 -0
  42. data/spec/snippr/processor/functions_spec.rb +72 -0
  43. data/spec/snippr/processor/links_spec.rb +12 -0
  44. data/spec/snippr/processor/wikilinks_spec.rb +12 -0
  45. data/spec/snippr/processor_spec.rb +35 -0
  46. data/spec/snippr/snip_spec.rb +179 -0
  47. data/spec/snippr/snippr_spec.rb +60 -55
  48. data/spec/snippr/view_helper_spec.rb +221 -0
  49. data/spec/spec_helper.rb +17 -3
  50. metadata +178 -87
  51. data/README.rdoc +0 -77
  52. data/lib/snippr/core_ext.rb +0 -12
  53. data/lib/snippr/helper.rb +0 -23
  54. data/lib/snippr/link.rb +0 -26
  55. data/spec/fixtures/tariff/einheit.snip +0 -1
  56. data/spec/fixtures/wiki.snip +0 -1
  57. 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
@@ -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 "snippr/core_ext"
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 Snippr::Path
13
- extend Snippr::I18n
14
- extend Snippr::Link
9
+ extend self
15
10
 
16
- class << self
17
-
18
- # The snippr file extension.
19
- FileExtension = ".snip"
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
- # The fallback tag for a missing snippr.
25
- MissingSnipprTag = '<samp class="missing snippr" />'
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
- # Expects the name of a snippr file. Also accepts a Hash of placeholders
29
- # to be replaced with dynamic values.
30
- def load(*args)
31
- @dynamics = args.last.kind_of?(Hash) ? args.pop : {}
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
- private
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
- # Returns the name of a snippr from a given Array of +args+.
39
- def name_from(args)
40
- args.map { |arg| arg.kind_of?(Symbol) ? arg.to_s.lower_camelcase : arg }.join("/") + locale
41
- end
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
- # Returns the raw snippr content or a +MissingSnipprTag+ in case the snippr
44
- # file does not seem to exist.
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
- # Returns the complete path to a snippr file.
54
- def file
55
- File.join path, [@name, FileExtension].join
56
- end
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
- # Replaces placeholders found in a given snippr +content+ with dynamic values.
59
- def insert_dynamics(content)
60
- @dynamics.each { |placeholder, value| content.gsub! "{#{placeholder}}", value.to_s }
61
- end
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
@@ -0,0 +1,3 @@
1
+
2
+
3
+
File without changes
@@ -0,0 +1,5 @@
1
+ ---
2
+ description: Die mit dem Fluegli
3
+ keywords: blau Mobilfunk GmbH, blau.de, blauworld, handy, sim
4
+ ---
5
+ <p>Broken!</p>
@@ -0,0 +1,5 @@
1
+ ---
2
+ description: Die mit dem Fluegli
3
+ keywords: blau Mobilfunk GmbH, blau.de, blauworld, handy, sim
4
+ ---
5
+ <p>So meta!</p>