Class: Curlybars::RenderingSupport
- Inherits:
-
Object
- Object
- Curlybars::RenderingSupport
- Defined in:
- lib/curlybars/rendering_support.rb
Instance Method Summary collapse
- #cached_call(meth) ⇒ Object
- #call(helper, helper_path, helper_position, arguments, options, &block) ⇒ Object
- #check_context_is_hash_or_enum_of_presenters(collection, path, position) ⇒ Object
- #check_context_is_presenter(context, path, position) ⇒ Object
- #check_timeout! ⇒ Object
- #coerce_to_hash!(collection, path, position) ⇒ Object
-
#initialize(timeout, contexts, variables, file_name, global_helpers_providers = [], cache = ->(key, &block) { block.call }, start_time: nil, depth: 0, partial_provider: nil) ⇒ RenderingSupport
constructor
A new instance of RenderingSupport.
- #optional_presenter_cache(presenter, template_cache_key, buffer) ⇒ Object
- #path(path, position) ⇒ Object
- #position(line_number, line_offset) ⇒ Object
- #presenter?(context) ⇒ Boolean
- #presenter_collection?(collection) ⇒ Boolean
- #render_partial(source, name, options) ⇒ Object
- #resolve_partial(name) ⇒ Object
- #to_bool(condition) ⇒ Object
- #variable(variable_path, position) ⇒ Object
Constructor Details
#initialize(timeout, contexts, variables, file_name, global_helpers_providers = [], cache = ->(key, &block) { block.call }, start_time: nil, depth: 0, partial_provider: nil) ⇒ RenderingSupport
Returns a new instance of RenderingSupport.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/curlybars/rendering_support.rb', line 3 def initialize(timeout, contexts, variables, file_name, global_helpers_providers = [], cache = ->(key, &block) { block.call }, start_time: nil, depth: 0, partial_provider: nil) @timeout = timeout @start_time = start_time || Time.now @depth = depth @contexts = contexts @variables = variables @file_name = file_name @cached_calls = {} @cache = cache @global_helpers_providers = global_helpers_providers @partial_provider = partial_provider @global_helpers = {} global_helpers_providers.each do |provider| provider.allowed_methods.each do |global_helper_name| symbol = global_helper_name.to_sym @global_helpers[symbol] = provider.method(symbol) end end end |
Instance Method Details
#cached_call(meth) ⇒ Object
110 111 112 113 114 |
# File 'lib/curlybars/rendering_support.rb', line 110 def cached_call(meth) return cached_calls[meth] if cached_calls.key? meth instrument(meth) { cached_calls[meth] = meth.call(*arguments_for_signature(meth, [], {})) } end |
#call(helper, helper_path, helper_position, arguments, options, &block) ⇒ Object
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/curlybars/rendering_support.rb', line 116 def call(helper, helper_path, helper_position, arguments, , &block) parameters = helper.parameters parameter_types = parameters.map(&:first) # parameters has value [[:rest]] when the presenter is using method_missing to catch all calls has_invalid_parameters = parameter_types.map { |type| type != :req }.any? && parameter_types != [:rest] if has_invalid_parameters source_location = helper.source_location file_path = source_location ? source_location.first : "n/a" line_number = source_location ? helper.source_location.last : "n/a" = "#{file_path}:#{line_number} - `#{helper_path}` bad signature " << "for #{helper} - helpers must have only required parameters" raise Curlybars::Error::Render.new('invalid_helper_signature', , helper_position) end instrument(helper) do helper.call(*arguments_for_signature(helper, arguments, ), &block) end end |
#check_context_is_hash_or_enum_of_presenters(collection, path, position) ⇒ Object
41 42 43 44 45 46 |
# File 'lib/curlybars/rendering_support.rb', line 41 def check_context_is_hash_or_enum_of_presenters(collection, path, position) return if presenter_collection?(collection) = "`#{path}` is not an array of presenters or a hash of such" raise Curlybars::Error::Render.new('context_is_not_an_array_of_presenters', , position) end |
#check_context_is_presenter(context, path, position) ⇒ Object
34 35 36 37 38 39 |
# File 'lib/curlybars/rendering_support.rb', line 34 def check_context_is_presenter(context, path, position) return if presenter?(context) = "`#{path}` is not a context type object" raise Curlybars::Error::Render.new('context_is_not_a_presenter', , position) end |
#check_timeout! ⇒ Object
26 27 28 29 30 31 32 |
# File 'lib/curlybars/rendering_support.rb', line 26 def check_timeout! return unless timeout.present? return unless (Time.now - start_time) > timeout = "Rendering took too long (> #{timeout} seconds)" raise ::Curlybars::Error::Render.new('timeout', , nil) end |
#coerce_to_hash!(collection, path, position) ⇒ Object
142 143 144 145 146 147 148 149 150 151 |
# File 'lib/curlybars/rendering_support.rb', line 142 def coerce_to_hash!(collection, path, position) check_context_is_hash_or_enum_of_presenters(collection, path, position) if collection.is_a?(Hash) collection elsif collection.respond_to?(:each_with_index) collection.each_with_index.to_h { |value, index| [index, value] } else raise "Collection is not coerceable to hash" end end |
#optional_presenter_cache(presenter, template_cache_key, buffer) ⇒ Object
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/curlybars/rendering_support.rb', line 165 def optional_presenter_cache(presenter, template_cache_key, buffer) presenter_cache_key = presenter.respond_to?(:cache_key) ? presenter.cache_key : nil if presenter_cache_key cache_key = "#{presenter_cache_key}/#{template_cache_key}" buffer << cache.call(cache_key) do # Output from the block must be isolated from the main output buffer SafeBuffer.new.tap do |cache_buffer| yield cache_buffer end end else yield buffer end end |
#path(path, position) ⇒ Object
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/curlybars/rendering_support.rb', line 71 def path(path, position) return global_helpers[path.to_sym] if global_helpers.key?(path.to_sym) check_traverse_not_too_deep(path, position) path_split_by_slashes = path.split('/') backward_steps_on_contexts = path_split_by_slashes.count - 1 base_context_position = contexts.length - backward_steps_on_contexts return -> {} unless base_context_position > 0 base_context_index = base_context_position - 1 base_context = contexts[base_context_index] dotted_path_side = path_split_by_slashes.last chain = dotted_path_side.split('.') method_to_return = chain.pop resolved = chain.inject(base_context) do |context, meth| next context if meth == 'this' next context.count if meth == 'length' && presenter_collection?(context) raise_if_not_traversable(context, meth, position) outcome = instrument(context.method(meth)) { context.public_send(meth) } return -> {} if outcome.nil? outcome end return -> { resolved } if method_to_return == 'this' if method_to_return == 'length' && presenter_collection?(resolved) return -> { resolved.count } end raise_if_not_traversable(resolved, method_to_return, position) resolved.method(method_to_return.to_sym) end |
#position(line_number, line_offset) ⇒ Object
138 139 140 |
# File 'lib/curlybars/rendering_support.rb', line 138 def position(line_number, line_offset) Curlybars::Position.new(file_name, line_number, line_offset) end |
#presenter?(context) ⇒ Boolean
153 154 155 |
# File 'lib/curlybars/rendering_support.rb', line 153 def presenter?(context) context.respond_to?(:allows_method?) end |
#presenter_collection?(collection) ⇒ Boolean
157 158 159 160 161 162 163 |
# File 'lib/curlybars/rendering_support.rb', line 157 def presenter_collection?(collection) collection = collection.values if collection.is_a?(Hash) collection.respond_to?(:each) && collection.all? do |presenter| presenter?(presenter) end end |
#render_partial(source, name, options) ⇒ Object
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/curlybars/rendering_support.rb', line 193 def render_partial(source, name, ) return "" if depth >= ::Curlybars.configuration.partial_nesting_limit compiled = ::Curlybars.compile(source, "partial:#{name}") eval_source = <<-RUBY rendering_context = { start_time: @start_time, depth: @depth + 1 } presenter = ::Curlybars::PartialPresenter.new(nil, options) global_helpers_providers = @global_helpers_providers partial_provider = @partial_provider #{compiled} RUBY eval(eval_source) # rubocop:disable Security/Eval -- eval is the established compilation pattern for the whole engine rescue Curlybars::Error::Render => e raise if e.id == 'render.timeout' || e.id == 'render.output_too_long' "" rescue StandardError "" end |
#resolve_partial(name) ⇒ Object
182 183 184 185 186 187 188 189 190 191 |
# File 'lib/curlybars/rendering_support.rb', line 182 def resolve_partial(name) return nil unless partial_provider source = partial_provider.resolve_partial(name) return nil unless source raise TypeError, "resolve_partial must return a String, got #{source.class}" unless source.is_a?(String) source end |
#to_bool(condition) ⇒ Object
48 49 50 51 52 53 54 55 |
# File 'lib/curlybars/rendering_support.rb', line 48 def to_bool(condition) condition != false && condition != [] && condition != {} && condition != 0 && condition != '' && !condition.nil? end |
#variable(variable_path, position) ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/curlybars/rendering_support.rb', line 57 def variable(variable_path, position) check_traverse_not_too_deep(variable_path, position) variable_split_by_slashes = variable_path.split('/') variable = variable_split_by_slashes.last.to_sym backward_steps_on_variables = variable_split_by_slashes.count - 1 variables_position = variables.length - backward_steps_on_variables scope = variables.first(variables_position).reverse.find do |vars| vars.key? variable end scope[variable] if scope end |