lesmok 0.2.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 17819eb07b14118356c7b0bc52573cd7d0e649b4
4
+ data.tar.gz: 2cd95f97b6a584a5ef855b67562085f7ab3854d6
5
+ SHA512:
6
+ metadata.gz: 4210bd01b9e0fbad2a799c486f8264509db2d9ecdaf2611bce6521851756046b63fc5fd8daaf461eefefc1a237721b4a7aff16a37e55c3ea836fbf470309fcbc
7
+ data.tar.gz: 8072cd00bdc59f49b299465e7a8031e9e962d9b15c8702bed003695b9f8bf8955b8e7209f51c2eb56eaad22b07b0d19c131c2a3e854787e7174af04c0c28de9e
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in lesmok.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Sixty AS
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,119 @@
1
+ # Lesmok
2
+
3
+ Liquid ExtentionS for MOre Komfort
4
+
5
+ ## Liquid markup language
6
+
7
+ Read about Liquid at:
8
+
9
+ - http://liquidmarkup.org/
10
+ - https://github.com/Shopify/liquid
11
+
12
+ # Using Lesmok
13
+
14
+ ## Drop the Base...
15
+
16
+ Make any class "meltable" quickly:
17
+
18
+ ```ruby
19
+ class FilmFanatic::Movie
20
+ include ::Lesmok::Acid::Meltable
21
+ end
22
+ ```
23
+
24
+ ... and you can start using it in your Liquid templates immediately.
25
+
26
+ NOTE: All methods are now delegated (ACID - All Content Is Delegated),
27
+ so you don't want to do this if your liquid templates are "untrustworthy"
28
+ or your object has potentially destructive methods.
29
+
30
+ ## Control the Beat...
31
+
32
+ The `Lesmok::Acid::Drop` liquid-drop class is used by default unless you:
33
+
34
+ - specify a `to_liquid` method explicitly in your class,
35
+ - override `liquify_drop_klass` to return your preferred sub-class of `Liquid::Drop`,
36
+ - or create an adjacent `*Drop` class with same naming as your model class.
37
+
38
+ ```ruby
39
+ class FilmFanatic::MovieDrop < ::Lesmok::Acid::Drop # Quick-n-dirty start.
40
+ alias :movie :source_object # For readability.
41
+ def rave # Start adding presenter methods you need.
42
+ "OMG! #{movie.title} is so awesome!"
43
+ end
44
+ end
45
+ ```
46
+
47
+ As you clean up, you may want to have more explicit drop control and migrate away from using Acid Drop:
48
+
49
+ ```ruby
50
+ class FilmFanatic::MovieDrop < ::Liquid::Drop
51
+ include ::Lesmok::Acid::Droppable # To keep compatible with Acid::Drop
52
+ alias :movie :source_object
53
+ end
54
+ ```
55
+
56
+
57
+ ## Keep your cache
58
+
59
+ Given that your object has a cache key, you can use the `cached_include` tag in your liquid templates:
60
+
61
+ ```ruby
62
+ class FilmFanatic::Movie
63
+ include ::Lesmok::Acid::Meltable
64
+ def cache_key
65
+ "fantastic-movie-#{self.imdb_id}"
66
+ end
67
+ end
68
+ ```
69
+
70
+ Then from your template:
71
+
72
+ ```liquid
73
+ {% cached_include 'my/movie/reviews/liquid/template' for { cache_on: fantastic_movie } %}
74
+ ```
75
+
76
+
77
+ # Installation
78
+
79
+ ## Get tha gem...
80
+
81
+ Add this line to your application's Gemfile:
82
+
83
+ gem 'lesmok'
84
+
85
+ And then execute:
86
+
87
+ $ bundle
88
+
89
+ Or install it yourself as:
90
+
91
+ $ gem install lesmok
92
+
93
+
94
+ ## Initialization and configuration
95
+
96
+
97
+ ```ruby
98
+ Lesmok.configure do |conf|
99
+ conf.logger = Rails.logger
100
+ conf.available_cache_stores = {
101
+ default: Rails.cache,
102
+ redis: $redis # Using Redis is entirely optional.
103
+ }
104
+ conf.debugging_enabled = Rails.env.development?
105
+ conf.caching_enabled = proc { Rails.env.production? }
106
+ conf.raise_errors_enabled = Rails.env.development?
107
+ end
108
+ Lesmok::Liquid::Tags.register_tags
109
+ ```
110
+
111
+
112
+
113
+ ## Contributing
114
+
115
+ 1. Fork it
116
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
117
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
118
+ 4. Push to the branch (`git push origin my-new-feature`)
119
+ 5. Create new Pull Request
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/clean'
4
+ require 'rspec/core/rake_task'
5
+
6
+ Bundler::GemHelper.install_tasks
7
+
8
+ CLEAN.add('pkg')
9
+
10
+ desc 'Run all examples'
11
+ RSpec::Core::RakeTask.new('spec')
12
+
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lesmok/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "lesmok"
8
+ spec.version = Lesmok::VERSION
9
+ spec.authors = ["Sixty AS", "Kent Dahl"]
10
+ spec.email = ["info@sixty.no", "kent@sixty.no"]
11
+ spec.summary = %q{Liquid ExtentionS for MOre Komfort}
12
+ spec.description = %q{Collection of utility classes, tags etc for use with the Liquid templating system.}
13
+ spec.homepage = "https://github.com/sixtyno/lesmok"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake", "~>0"
23
+
24
+ spec.add_dependency 'activesupport' # , '~> 3.2'
25
+ spec.add_dependency 'liquid' #, '~> 2.5'
26
+
27
+ spec.add_development_dependency 'rspec', '~>3.0'
28
+
29
+ end
@@ -0,0 +1,20 @@
1
+ require 'lesmok/version'
2
+ require 'lesmok/config'
3
+ require 'lesmok/tags'
4
+ require 'lesmok/acid'
5
+ require 'lesmok/backwards_compatibility'
6
+
7
+ module Lesmok
8
+ module ClassMethods
9
+ def config
10
+ @configuration ||= Config.new
11
+ end
12
+ def configure
13
+ yield(config)
14
+ end
15
+ def logger
16
+ config.logger
17
+ end
18
+ end
19
+ extend ClassMethods
20
+ end
@@ -0,0 +1,11 @@
1
+ require 'liquid'
2
+ require 'lesmok/caching/helpers'
3
+ require 'lesmok/acid/meltable'
4
+ require 'lesmok/acid/drop'
5
+
6
+
7
+ module Lesmok
8
+ module Acid
9
+ # ...
10
+ end
11
+ end
@@ -0,0 +1,64 @@
1
+ module Lesmok
2
+ module Acid
3
+
4
+ ##
5
+ # Base module for creating liquid drops
6
+ # which defaults to allowing maximum access
7
+ # class for liquid drops used with Lesmok.
8
+ #
9
+ module Droppable
10
+ include Helpers
11
+
12
+ attr_reader :source_object # Object we delegate to
13
+ attr_reader :acid_options # Any customization options.
14
+ def initialize(source, opts = {})
15
+ @source_object = source
16
+ @acid_options = opts
17
+ end
18
+
19
+ ## Liquify...
20
+ def to_liquid
21
+ self
22
+ end
23
+
24
+ ## Solidify
25
+ def to_solid
26
+ @source_object
27
+ end
28
+
29
+ ## We default to sending anything through to the source object.
30
+ def before_method(method_name)
31
+ if allow_delegating_method_to_source?(method_name)
32
+ return @source_object.send(method_name)
33
+ else
34
+ msg = "[#{self.class}] The method `#{method_name}` is not defined on #{@source_object.inspect[0..127]}."
35
+ Lesmok.logger.warn(msg) if Lesmok.config.debugging?
36
+ raise NotImplementedError.new(msg) if Lesmok.config.raise_errors?
37
+ end
38
+ end
39
+
40
+ def allow_delegating_method_to_source?(name)
41
+ @source_object.respond_to?(name) # TODO: && !name =~ /(\!\=)$/
42
+ end
43
+
44
+ def respond_to_missing?(method_name, include_private = false)
45
+ allow_delegating_method_to_source?(method_name) || super
46
+ end
47
+
48
+ ## Ensure before_method fallbacks are used both from liquid and when using drop directly.
49
+ def method_missing(method_name, *args)
50
+ (args.present?) ? super(method_name, *args) : before_method(method_name)
51
+ end
52
+
53
+ end
54
+
55
+ ##
56
+ # Base fallback class for creating Liquid drops with Lesmok
57
+ #
58
+ class Drop < ::Liquid::Drop
59
+ include Droppable
60
+ end
61
+
62
+
63
+ end
64
+ end
@@ -0,0 +1,59 @@
1
+ module Lesmok
2
+ module Acid
3
+
4
+ module Helpers
5
+ ##
6
+ # Short-hands for use when switching context
7
+ # between liquid and Ruby code, to ensure
8
+ # you get the drop OR the solid source, w/o any overhead.
9
+ #
10
+ def melt ; to_liquid ; end # "Melts" the object into a liquid.
11
+ def cast ; to_solid ; end # "Casts" (as in metal forging) back into the original object.
12
+ def solid ; to_solid ; end
13
+ end
14
+
15
+ ##
16
+ # Indicate that a model can be liquified.
17
+ #
18
+ module Meltable
19
+ include Helpers
20
+
21
+ ## Liquify...
22
+ def to_liquid
23
+ @liquid_drop ||= liquify_dynamically
24
+ end
25
+
26
+ ## Solidify
27
+ def to_solid
28
+ self
29
+ end
30
+
31
+ ##
32
+ # Fallback to trying to find the drop class dynamically
33
+ # or use generic AcidDrop if it can't be found.
34
+ #
35
+ def liquify_dynamically
36
+ return @liquid_drop if @liquid_drop
37
+ klass = liquify_drop_klass || AcidDrop
38
+ @liquid_drop = klass.new(self)
39
+ end
40
+
41
+ ##
42
+ # We expect Drop classes to be in same namespace as the object class.
43
+ #
44
+ def liquify_drop_klass
45
+ str = self.class.name + 'Drop'
46
+ klass = str.split('::').inject(Object) do |mod, class_name|
47
+ mod.const_get(class_name)
48
+ end
49
+ klass
50
+ rescue NameError => err
51
+ msg = "[#{self.class}] Could not find liquid drop class..."
52
+ ::Lesmok.logger.warn(msg) if Lesmok.config.debugging?
53
+ Drop
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,13 @@
1
+ module Lesmok
2
+ ##
3
+ # Deprecated namespace.
4
+ #
5
+ module Liquid
6
+ module Dropping
7
+ AcidDrop = ::Lesmok::Acid::Drop
8
+ AcidMeltable = ::Lesmok::Acid::Meltable
9
+ end
10
+ Tags = ::Lesmok::Tags
11
+ CachingHelpers = ::Lesmok::Caching::Helpers
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ require 'active_support'
2
+ module Lesmok
3
+ module Caching
4
+ module Helpers
5
+
6
+ module ExpiryCalculation
7
+ def calculate_expiry(cached_on_obj = nil, expire_in_option = nil, jitter_factor = 0.05)
8
+ expire_in ||= cached_on_obj && cached_on_obj.respond_to?(:cache_expire_in) && cached_on_obj.cache_expire_in
9
+ expire_in ||= (expire_in_option || 5).to_i * 60 # TODO: Is option authorative or fallback only?
10
+ expire_in += rand * expire_in * jitter_factor if jitter_factor # 5 % random additional time to avoid all expiring at once.
11
+ expire_in
12
+ end
13
+ extend self
14
+ end
15
+ module GlobalKeyHandling
16
+ def global_cache_scope
17
+ "Lesmok:Liquid"
18
+ end
19
+ def full_cache_key_for(cached_on_obj, template_name, global_scope = nil)
20
+ cache_val = cached_on_obj.to_s if cached_on_obj.kind_of?(String)
21
+ cache_val ||= cached_on_obj.respond_to?(:cache_key) && cached_on_obj.cache_key
22
+ "#{global_scope || global_cache_scope}:#{I18n.locale}:cached_include:#{template_name}:#{cache_val}"
23
+ end
24
+ extend self
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,39 @@
1
+ module Lesmok
2
+ class Config
3
+ attr_accessor :logger
4
+ attr_accessor :cache
5
+ attr_accessor :caching_enabled
6
+ attr_accessor :available_cache_stores
7
+ attr_accessor :debugging_enabled
8
+ attr_accessor :raise_errors_enabled
9
+
10
+ alias :raise_errors? :raise_errors_enabled
11
+ alias :debugging? :debugging_enabled
12
+
13
+ def logger
14
+ @logger ||= (rails? && ::Rails.logger)
15
+ end
16
+
17
+ def cache
18
+ @cache ||= find_cache_store(:default) || (rails? && ::Rails.cache) || nil
19
+ end
20
+
21
+ def caching?
22
+ return false if !@caching_enabled
23
+ @caching_enabled.kind_of?(Proc) ? @caching_enabled.call : true
24
+ end
25
+
26
+ def find_cache_store(name = nil)
27
+ name ||= :default
28
+ avail_stores = (available_cache_stores || {})
29
+ store = avail_stores[name.to_sym]
30
+ store ||= avail_stores[:default]
31
+ store ||= cache
32
+ end
33
+
34
+ def rails?
35
+ Object.const_defined? "Rails"
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,21 @@
1
+ require 'liquid'
2
+
3
+ # Optional `to_liquid` definitions injected into various classes.
4
+ #
5
+ # Require this file explicitly to use.
6
+
7
+ class Symbol
8
+ def to_liquid
9
+ to_s
10
+ end
11
+ end
12
+
13
+ class Struct
14
+ def to_liquid
15
+ hash = Hash.new
16
+ self.members.each do |k|
17
+ hash[k.to_s] = self[k]
18
+ end
19
+ hash
20
+ end
21
+ end
@@ -0,0 +1,75 @@
1
+ ##
2
+ #
3
+ # To register for use in Rails:
4
+ # ActionView::Template.register_template_handler :liquid, ::Lesmok::Railing::ActionViewHandler'
5
+ #
6
+ # Based on example by Roy van der Meij:
7
+ # - http://royvandermeij.com/blog/2011/09/21/create-a-liquid-handler-for-rails-3-dot-1/
8
+ #
9
+ module Lesmok
10
+ module Railing
11
+
12
+ class ActionViewHandler
13
+ def self.lesmok_options
14
+ @lesmok_options ||= {}
15
+ end
16
+
17
+ def self.call(template)
18
+ "#{self}.new(self).render(#{template.source.inspect}, local_assigns)"
19
+ end
20
+
21
+ def initialize(view)
22
+ @view = view
23
+ end
24
+
25
+ def render(template, local_assigns = {})
26
+ @view.controller.headers["Content-Type"] ||= 'text/html; charset=utf-8'
27
+
28
+ assigns = @view.assigns
29
+
30
+ if @view.content_for?(:layout)
31
+ assigns["content_for_layout"] = @view.content_for(:layout)
32
+ end
33
+ assigns.merge!(local_assigns.stringify_keys)
34
+
35
+ controller = @view.controller
36
+ filters = if controller.respond_to?(:liquid_filters, true)
37
+ controller.send(:liquid_filters)
38
+ elsif controller.respond_to?(:master_helper_module)
39
+ [controller.master_helper_module]
40
+ else
41
+ [controller._helpers]
42
+ end
43
+
44
+ liquid = ::Liquid::Template.parse(template)
45
+ render_assigns = assigns.with_indifferent_access
46
+ render_opts = {:filters => filters, :registers => {:action_view => @view, :controller => @view.controller}}
47
+ if self.class.lesmok_options[:rethrow_errors]
48
+ text = liquid.render!(render_assigns, render_opts)
49
+ else
50
+ text = liquid.render(render_assigns, render_opts)
51
+ end
52
+ if ::Lesmok.config.debugging?
53
+ log_any_liquid_errors(liquid.errors)
54
+ log_any_liquid_errors(liquid.warnings, 'warning')
55
+ end
56
+
57
+ text.html_safe
58
+ end
59
+
60
+ def log_any_liquid_errors(errors, type_str = 'error')
61
+ return if errors.blank?
62
+ log = ::Rails.logger
63
+ log.warn "[Lesmok] Template #{type_str}s (#{errors.size}) detected!"
64
+ errors.each do |err|
65
+ log.debug " -- Liquid #{type_str}: #{err}"
66
+ end
67
+ end
68
+
69
+ def compilable?
70
+ false
71
+ end
72
+ end
73
+
74
+ end # Liquid
75
+ end # Lesmok
@@ -0,0 +1,51 @@
1
+ require 'liquid'
2
+
3
+ require 'lesmok/tags/error_logging'
4
+ require 'lesmok/tags/cached_include'
5
+ require 'lesmok/tags/erb_include'
6
+
7
+ module Lesmok
8
+ module Tags
9
+
10
+ def self.register_tags
11
+ ::Liquid::Template.register_tag('erb_include', ::Lesmok::Tags::ErbInclude)
12
+ ::Liquid::Template.register_tag('cached_include', ::Lesmok::Tags::CachedInclude)
13
+ ::Liquid::Template.register_tag('debug_comment', ::Lesmok::Tags::DebugComment)
14
+ ::Liquid::Template.register_tag('include', ::Lesmok::Tags::DebugInclude) if Lesmok.config.debugging?
15
+ ::Liquid::Template.register_tag('csrf', ::Lesmok::Tags::Csrf)
16
+ end
17
+
18
+ class DebugComment < ::Liquid::Block
19
+ include ErrorLogging
20
+ def render(context)
21
+ return '' unless Lesmok.config.debugging?
22
+ with_exception_logging(context) do
23
+ "<!-- LIQUID DEBUG: #{super} -->"
24
+ end
25
+ end
26
+ end
27
+
28
+ class DebugInclude < ::Liquid::Include
29
+ include ErrorLogging
30
+ def render(context)
31
+ with_exception_logging(context) do
32
+ result = super
33
+ if context.errors.present?
34
+ ::Lesmok.logger.debug " -- Liquid errors (#{context.errors.size}) seen in: #{@template_name}"
35
+ end
36
+ result
37
+ end
38
+ end
39
+ end
40
+
41
+ class Csrf < ::Liquid::Tag
42
+ def render(context)
43
+ controller = context.registers[:controller]
44
+ name = controller.send(:request_forgery_protection_token).to_s
45
+ value = controller.send(:form_authenticity_token)
46
+ %(<input type="hidden" name="#{name}" value="#{value}">)
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,70 @@
1
+ require 'liquid'
2
+ require 'lesmok/caching/helpers'
3
+
4
+
5
+ module Lesmok
6
+ module Tags
7
+
8
+ class CachedInclude < ::Liquid::Include
9
+ include ErrorLogging
10
+
11
+ include ::Lesmok::Caching::Helpers
12
+ include ExpiryCalculation
13
+ extend GlobalKeyHandling
14
+
15
+ def render(context)
16
+ return super unless fragment_caching_enabled?
17
+ cached_on_obj = context[@attributes['cache_on']]
18
+ cache_val = cached_on_obj && cached_on_obj.respond_to?(:cache_key) && cached_on_obj.cache_key
19
+ cache_val ||= context[@attributes['cache_key']]
20
+
21
+ template_name = context[@template_name]
22
+
23
+ ## Catch cases where cached_include is used incorrectly.
24
+ if cache_val.blank?
25
+ if Lesmok.config.debugging?
26
+ Lesmok.logger.warn "[#{self.class}] No valid cache key given for '#{template_name}' template!"
27
+ Lesmok.logger.debug " -- No cache key given nor found for object: #{cached_on_obj.inspect.truncate(64)}"
28
+ end
29
+ if Lesmok.config.raise_errors?
30
+ raise ArgumentError.new("No valid cache key! given for '#{template_name}' template!")
31
+ end
32
+ end
33
+
34
+ return super unless cache_val.present?
35
+
36
+ ## Allow sub-scoping w/o manually creating cache key.
37
+ cache_subscope = context[@attributes['cache_scope']]
38
+ cache_val += ":SUBSCOPE-#{cache_subscope}" if cache_subscope.present?
39
+
40
+ expire_in = calculate_expiry(cached_on_obj, context[@attributes['expire_in']])
41
+ cache_key = self.class.full_cache_key_for(cache_val, template_name)
42
+ cache_store = select_cache_store_for(context)
43
+ Lesmok.logger.debug "[#{self.class}] Lookup #{cache_key} in #{cache_store}..." if Lesmok.config.debugging?
44
+ result = cache_store.fetch(cache_key, expires_in: expire_in) do
45
+ Lesmok.logger.debug "[#{self.class}] --- cache miss on #{cache_key} in #{cache_store}!" if Lesmok.config.debugging?
46
+ super
47
+ end
48
+
49
+ if context.errors.present?
50
+ ::Lesmok.logger.debug " -- Liquid errors (#{context.errors.size}) seen in: #{@template_name}"
51
+ end
52
+
53
+ result
54
+ rescue Exception => err
55
+ log_exception(err, context)
56
+ ""
57
+ end
58
+
59
+ def select_cache_store_for(context)
60
+ cache_store_name = context[@attributes['cache_store']]
61
+ cache_store = Lesmok.config.find_cache_store(cache_store_name)
62
+ end
63
+
64
+ def fragment_caching_enabled?
65
+ Lesmok.config.caching?
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,53 @@
1
+ require 'liquid'
2
+
3
+ module Lesmok
4
+ module Tags
5
+
6
+ class ErbInclude < ::Liquid::Include
7
+ include ErrorLogging
8
+
9
+ class ErbRenderer
10
+ attr_reader :context
11
+ def initialize(liquid_context, template_name)
12
+ @context = liquid_context
13
+ @template_name = template_name
14
+ end
15
+ def extract_vars
16
+ # Not needed if we use action_view directly?
17
+ ctrl.instance_variables.each do |key|
18
+ val = ctrl.instance_variable_get(key)
19
+ self.instance_variable_set(key, val)
20
+ end if ctrl
21
+ end
22
+
23
+ def ctrl
24
+ context.registers[:controller]
25
+ end
26
+
27
+ def view
28
+ context.registers[:action_view]
29
+ end
30
+
31
+ def call(args = {})
32
+ template_name = context[@template_name]
33
+ default_args = {
34
+ partial: template_name,
35
+ template: template_name,
36
+ registers: context.registers,
37
+ locals: context.scopes.last.with_indifferent_access, # TODO: Make this work?
38
+ liquid_context: context,
39
+ }
40
+ render_args = default_args.merge(args)
41
+ ctrl.send(:render, render_args)
42
+ end
43
+ end
44
+ def render(context)
45
+ with_exception_logging(context) do
46
+ erb = ErbRenderer.new(context, @template_name)
47
+ erb.call
48
+ end
49
+ end
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,27 @@
1
+ module Lesmok
2
+ module Tags
3
+
4
+ module ErrorLogging
5
+ def log_exception(err, context)
6
+ template_name = context[@template_name]
7
+ err.message << " (in template '#{template_name}')" rescue nil
8
+ err.blame_file! "#{template_name}.liquid" rescue nil
9
+ Lesmok.logger.error "[#{self.class}] Liquid error in '#{template_name}': #{err.to_s} \n - #{err.backtrace.first(15).join("\n - ")}"
10
+ rescue => err
11
+ Lesmok.logger.error "[#{self.class}] META ERROR: Liquid exception reporting failure: #{err.to_s} \n - #{err.backtrace.first(15).join("\n - ")}"
12
+ ensure
13
+ raise err if Lesmok.config.debugging?
14
+ ""
15
+ end
16
+
17
+ def with_exception_logging(context)
18
+ begin
19
+ yield
20
+ rescue => err
21
+ log_exception(err, context)
22
+ end
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module Lesmok
2
+ VERSION = "0.2.0.pre1"
3
+ end
@@ -0,0 +1,14 @@
1
+ require 'lesmok'
2
+ describe ::Lesmok::Caching::Helpers do
3
+
4
+ describe described_class::ExpiryCalculation do
5
+ it "should calculate expiry" do
6
+ exp = described_class.calculate_expiry
7
+ expect(exp).to be >= 300
8
+ expect(exp).to be <= 315
9
+
10
+ expect(described_class.calculate_expiry(nil, 10, nil)).to be == 600
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,28 @@
1
+ require 'lesmok'
2
+ describe ::Lesmok::Config do
3
+
4
+ it "should lookup cache with fallback" do
5
+ config = described_class.new
6
+ dummy_cache = double
7
+ config.cache = dummy_cache
8
+
9
+ expect(config.cache).to be == dummy_cache
10
+ expect(config.find_cache_store).to be == dummy_cache
11
+ expect(config.find_cache_store(nil)).to be == dummy_cache
12
+ expect(config.find_cache_store(:default)).to be == dummy_cache
13
+ expect(config.find_cache_store(:unknown)).to be == dummy_cache
14
+ end
15
+
16
+ it "should allow caching to be toggled dynamically" do
17
+ config = described_class.new
18
+ cache_level = 1
19
+ config.caching_enabled = proc { cache_level > 1 }
20
+ expect(config.caching?).to be false
21
+ cache_level = 2
22
+ expect(config.caching?).to be true
23
+ cache_level = 0
24
+ expect(config.caching?).to be false
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,28 @@
1
+ require 'lesmok/liquidations'
2
+
3
+ describe 'Lesmok liquidations' do
4
+
5
+ describe 'Symbols' do
6
+ let(:template){ Liquid::Template.parse("GOT:{{ sym }}") }
7
+ it "should render symbols" do
8
+ text = template.render( 'sym' => :symbol )
9
+ expect(text).to include "GOT:symbol"
10
+ end
11
+ end
12
+
13
+ describe 'Structs' do
14
+ let(:anon_klass){ Struct.new(:name, :age) }
15
+ let(:template){ Liquid::Template.parse("{{ user.name }}/{{ user.age }}") }
16
+ it "should handle structs" do
17
+ user = anon_klass.new("OlaNordmann", 77)
18
+ expect(user.age).to eql(77)
19
+ text = template.render( 'user' => user )
20
+ expect(text).to include "OlaNordmann"
21
+ expect(text).to include "77"
22
+ end
23
+
24
+ end
25
+
26
+
27
+
28
+ end
@@ -0,0 +1,24 @@
1
+ require 'lesmok'
2
+ describe ::Lesmok::Tags do
3
+
4
+ before(:all) do
5
+ described_class.register_tags
6
+ end
7
+
8
+ describe described_class::DebugComment do
9
+ let(:template){ Liquid::Template.parse("{% debug_comment %} HUH HUH {% enddebug_comment %}") }
10
+ it "should render contents in debugging mode" do
11
+ Lesmok.config.debugging_enabled = true
12
+ text = template.render
13
+ expect(text).to include "HUH HUH"
14
+ expect(text).to include "<!--"
15
+ end
16
+
17
+ it "should not render contents by default" do
18
+ Lesmok.config.debugging_enabled = false
19
+ text = template.render
20
+ expect(text).to be == ""
21
+ end
22
+ end
23
+
24
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lesmok
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0.pre1
5
+ platform: ruby
6
+ authors:
7
+ - Sixty AS
8
+ - Kent Dahl
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-08-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.5'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.5'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: activesupport
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: liquid
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rspec
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '3.0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '3.0'
84
+ description: Collection of utility classes, tags etc for use with the Liquid templating
85
+ system.
86
+ email:
87
+ - info@sixty.no
88
+ - kent@sixty.no
89
+ executables: []
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - Gemfile
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - lesmok.gemspec
98
+ - lib/lesmok.rb
99
+ - lib/lesmok/acid.rb
100
+ - lib/lesmok/acid/drop.rb
101
+ - lib/lesmok/acid/meltable.rb
102
+ - lib/lesmok/backwards_compatibility.rb
103
+ - lib/lesmok/caching/helpers.rb
104
+ - lib/lesmok/config.rb
105
+ - lib/lesmok/liquidations.rb
106
+ - lib/lesmok/railing/action_view_handler.rb
107
+ - lib/lesmok/tags.rb
108
+ - lib/lesmok/tags/cached_include.rb
109
+ - lib/lesmok/tags/erb_include.rb
110
+ - lib/lesmok/tags/error_logging.rb
111
+ - lib/lesmok/version.rb
112
+ - spec/lesmok/caching_helpers_spec.rb
113
+ - spec/lesmok/config_spec.rb
114
+ - spec/lesmok/liquidations_spec.rb
115
+ - spec/lesmok/tags_spec.rb
116
+ homepage: https://github.com/sixtyno/lesmok
117
+ licenses:
118
+ - MIT
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">"
132
+ - !ruby/object:Gem::Version
133
+ version: 1.3.1
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.4.5
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: Liquid ExtentionS for MOre Komfort
140
+ test_files:
141
+ - spec/lesmok/caching_helpers_spec.rb
142
+ - spec/lesmok/config_spec.rb
143
+ - spec/lesmok/liquidations_spec.rb
144
+ - spec/lesmok/tags_spec.rb
145
+ has_rdoc: