Class: Skyline::Rendering::Renderer

Inherits:
Object
  • Object
show all
Defined in:
lib/skyline/rendering/renderer.rb

Overview

The skyline renderer renders all Articles, Sections and basically anything that’s renderable or previewable in Skyline.

Direct Known Subclasses

Skyline::Renderer

Defined Under Namespace

Modules: Helpers

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Renderer

Creates a new renderer instance.

Parameters:

  • options (Hash) (defaults to: {})

    Options

Options Hash (options):

  • :assigns (Hash) — default: {}

    Assigns to pass to the template, all assigns are accessible by their instance variable. ‘:test` becomes @test in the template.

  • :controller (Controller) — default: nil

    The controller that is serving the current request.

  • :paths (Array<String,Pathname>) — default: ["app/templates", Skyline.root + "app/templates/skyline"]

    Paths that will be searched for templates.

  • :site (Site)

    The currently active site object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/skyline/rendering/renderer.rb', line 90

def initialize(options = {})
  options.reverse_merge!(:assigns => {}, 
                         :controller => nil, 
                         :paths => ["app/templates", Skyline.root + "app/templates/skyline"],
                         :site => nil)

  # The controller is optional!!
  @controller = options[:controller]
  @assigns = options[:assigns].update(:_controller => @controller, 
                                      :_site => options[:site])

  @template_paths = options[:paths].collect{|p| (Rails.root + p).to_s if File.exist?(Rails.root + p)}.compact
  @template_assigns = {}
end

Instance Attribute Details

#_configObject

Returns the value of attribute _config.



5
6
7
# File 'lib/skyline/rendering/renderer.rb', line 5

def _config
  @_config
end

#assignsObject (readonly)

Returns the value of attribute assigns.



4
5
6
# File 'lib/skyline/rendering/renderer.rb', line 4

def assigns
  @assigns
end

#template_pathsObject (readonly)

Returns the value of attribute template_paths.



4
5
6
# File 'lib/skyline/rendering/renderer.rb', line 4

def template_paths
  @template_paths
end

Class Method Details

.helper(module_name) ⇒ Object

Add a helper to the standard renderer

Parameters:

  • module_name (~to_s, Module)

    ] Module/module name to include in the helper for renderer.



55
56
57
# File 'lib/skyline/rendering/renderer.rb', line 55

def helper(module_name)
  Helpers.helper(module_name)
end

.register_renderables(type, renderables) ⇒ Object

Add your own renderables

Parameters:

  • type (Symbol)

    The type (for instance ‘:sections` or `:articles`) to register your renderables under

  • renderables (Array<String,Symbol,Class>)

    Your own renderables



41
42
43
# File 'lib/skyline/rendering/renderer.rb', line 41

def register_renderables(type, renderables)
  @@renderables[type] = renderables
end

.renderable_typesArray<Symbol>

All availables renderable types

Returns:

  • (Array<Symbol>)

    All available types



48
49
50
# File 'lib/skyline/rendering/renderer.rb', line 48

def renderable_types
  @@renderables.keys
end

.renderables(type, sub = :all) ⇒ Array<Class>

The list of renderable classes by type

Parameters:

  • type (Symbol)

    The type to get the renderable classes for

  • sub (Symbol, Class) (defaults to: :all)

    The sub class ie. :news_item or Skyline::Page when @@renderables is an Hash]

Returns:

  • (Array<Class>)

    Array of renderable classes



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/skyline/rendering/renderer.rb', line 20

def renderables(type, sub = :all)
  @@renderables ||= {}
  
  if @@renderables[type].kind_of?(Hash)
    @@renderables[type] ||= {}
    if sub == :all
      @@renderables[type][:all] = renderables_to_class(type, @@renderables[type].values.flatten.uniq)
    else
      sub = sub.name.underscore.to_sym if sub.kind_of?(Class)
      classes = @@renderables[type][sub] || @@renderables[type][:default]
      @@renderables[type][sub] = renderables_to_class(type, classes)
    end
  else
    @@renderables[type] = renderables_to_class(type, @@renderables[type])
  end
end

Instance Method Details

#config(options = {}) ⇒ Hash

TODO:

Check the exact syntax of options and what happens with the parameters of the :proxy. blocks.

The current rendering configuration

Parameters:

  • options (Hash) (defaults to: {})

    Options

Options Hash (options):

  • :additional_config (Hash) — default: {}

    An additional config to use just for this instance of the renderer. Setting :additional_config updates the config!

Returns:

  • (Hash)

    the current config



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/skyline/rendering/renderer.rb', line 277

def config(options = {})
  return self._config if self._config && Rails.env == "production"
  options.reverse_merge!(:additional_config => {})
  
  delegate_proc = Proc.new do |object| 
    {
      :class_name => "Skyline::ArticleVersion", 
      :path => object.article.class.name.sub(/^Skyline::/, '').underscore,
      :templates => self._config[object.article.class.name].andand[:templates] || []
    }
  end
  
  config = {"Skyline::Variant"      => delegate_proc,
            "Skyline::Publication"  => delegate_proc,
            "Skyline::Section"      => {:proxy => Proc.new{|renderer, section, options| renderer.render(section.sectionable, options)}},
           }.merge(options[:additional_config])
  
  self.class.renderable_types.each do |type|
    self.class.renderables(type).each do |renderable|
      name = renderable.name
      config[name] = {:class_name => name }
    end
  end

  config.each do |object, object_config|
    if object_config.kind_of?(Hash) && !object_config[:proxy]
      object_config[:path] ||= object_config[:class_name].sub(/^Skyline::/, '').underscore
      object_config[:templates] = templates_in_path(object_config[:path])
      object_config[:templates].sort!
    end
  end
  
  self._config = config
end

#file_path(object, filename) ⇒ Object



327
328
329
330
331
332
333
# File 'lib/skyline/rendering/renderer.rb', line 327

def file_path(object, filename)
  paths = object_template_paths(object)
  paths.each do |path|
    return File.join(path, filename) if File.exists?(File.join(path, filename))
  end
  nil
end

#objectrenderable

The current object that’s being rendered

Returns:

  • (renderable)

    The renderable object.



182
183
184
# File 'lib/skyline/rendering/renderer.rb', line 182

def object
  @_local_object
end

#object_template_paths(object) ⇒ Object



312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/skyline/rendering/renderer.rb', line 312

def object_template_paths(object)
  object_config = self.object_config(object)
  template = self.object_template(object)
  
  template_path = object_config[:path]
  path = "#{template_path}/#{template}"
  default_path = "#{template_path}/default"

  load_paths = []
  load_paths += @template_paths.collect{|p| File.join(p, path)}
  load_paths += @template_paths.collect{|p| File.join(p, template_path)}
  load_paths += @template_paths.collect{|p| File.join(p, default_path)} unless template == "default"
  load_paths
end

#peek(n = 1) ⇒ Array<renderable>

Peek looks forward N position in the current renderable collection. Peek does not modify the renderable collection.

Can only be used within a render_collection call.

Parameters:

  • n (Integer) (defaults to: 1)

    Number of items to look ahead

Returns:

  • (Array<renderable>)

    N renderable items (or less if the collection end has been reached)



194
195
196
197
# File 'lib/skyline/rendering/renderer.rb', line 194

def peek(n = 1)
  return [] if @_current_collection.blank?
  @_current_collection[@_current_collection_index + @_collection_skip + 1, n]
end

#peek_until {|i| ... } ⇒ Array<renderable>

Peek until the conditions in the passed block return true. Peek_until does not modify the renderable collection.

Can only be used within a render_collection call.

Yields:

  • (i)

    A block that must evaluate to true/false

Yield Parameters:

  • i (renderable)

    The current renderable item

Yield Returns:

  • (true, false)

    If true the collection from the entry point up until the moment the block returns true is returned as an array. If false the loop continues until the end of the collection is reached or the conditions in the block are met.

Returns:

  • (Array<renderable>)

    Renderable items.



211
212
213
214
215
216
217
218
219
220
221
# File 'lib/skyline/rendering/renderer.rb', line 211

def peek_until(&block)
  return [] if @_current_collection.blank?
  peeking = []
  items = @_current_collection[@_current_collection_index + @_collection_skip + 1 .. -1]
  return [] unless items
  items.each do |i|
    return peeking if yield i
    peeking << i
  end
  peeking
end

#render(object, options = {}) ⇒ String

Render one renderable object

Parameters:

  • object (renderable)

    A renderable object

  • options (Hash) (defaults to: {})

    Options

Options Hash (options):

  • :locals (Hash) — default: {}

    Locals to make available to the template

  • :assigns (Hash) — default: {}

    Assigns merged with the global assigns of this renderer

Returns:

  • (String)

    The rendered template



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/skyline/rendering/renderer.rb', line 114

def render(object, options = {})
  options.reverse_merge!(:locals => {}, :assigns => {})
  
  object_config = self.object_config(object)

  if object_config[:proxy]
    object_config[:proxy].call(self, object, options)
  else
    template = self.object_template(object)
    load_paths = self.object_template_paths(object)

    Rails.logger.debug "Rendering index template from paths: #{load_paths.join(', ')} (object.template = #{template})"

    av = ActionView::Base.new(load_paths.map(&:to_s))

    assigns = (options[:assigns] || {}).merge(self.assigns)
    assigns[:_template_assigns] = @template_assigns
    assigns[:_renderer] = self
    assigns[:_local_object_name] = object_config[:class_name].demodulize.underscore.to_sym
    assigns[:_local_object] = object
    
    av.assign(assigns)
    
    @_local_object = object   # for object function
    
    if @controller
      if @controller.respond_to?(:_routes)
        (class << av; self; end).send(:include, @controller._routes.url_helpers)
      end

      if @controller.respond_to?(:_helpers)
        (class << av; self; end).send(:include, @controller._helpers)
      end
    end
        
    av.extend Skyline::Rendering::Helpers::RendererHelper
    av.extend Helpers
    
    av.render(:file => "index", :locals => options[:locals]).html_safe
  end
end

#render_collection(objects, options = {}, &block) ⇒ String

Render a collection of objects (array), this gives support for peek() and skip!() in the templates. A template can decide too look n items forward and skip n items because the template itself rendered the next n items.

By default each object is rendered with the default rendering options. If you pass a block, this block is called for every item in the collection. The return value of the block will be added to the output. No automatic rendering will be done.

All assigns and template_assigns will be available to all (cloned) renderers. (This is because clone only makes a shallow clone, attributes (like assigns) which are Hashes aren’t copied: a clone uses the same memory address of the attribute.)

Parameters:

  • objects (Array<renderable>)

    An array of renderable objects.

  • options (Hash) (defaults to: {})

    Options will be passed to each consequent #render call.

Returns:

  • (String)

    The rendererd templates



175
176
177
# File 'lib/skyline/rendering/renderer.rb', line 175

def render_collection(objects, options = {}, &block)
  self.dup.send(:_render_collection, objects, options, &block)
end

#render_until(&block) ⇒ Object

Render_until does the same as peek_until but it also renders the objects and advances the collection pointer until the conditions in the block are met.

See Also:



227
228
229
# File 'lib/skyline/rendering/renderer.rb', line 227

def render_until(&block)
  peek_until(&block).collect{|i| self.skip!; self.render(i)}.join
end

#skip!(n = 1) ⇒ Object

Advances the collection pointer by one

Can only be used within a render_collection call.

Parameters:

  • n (Integer) (defaults to: 1)

    Number of items to skip



236
237
238
239
# File 'lib/skyline/rendering/renderer.rb', line 236

def skip!(n = 1)
  return 0 if @_current_collection.blank?    
  @_collection_skip += n
end

#skip_until!(&block) ⇒ Object

Skip_until! works like peek_until except it skips until the conditions in the passed block are met.

See Also:



245
246
247
248
249
250
251
252
253
# File 'lib/skyline/rendering/renderer.rb', line 245

def skip_until!(&block)
  return [] if @_current_collection.blank?
  items = @_current_collection[@_current_collection_index + @_collection_skip + 1 .. -1]
  return [] unless items
  items.each do |i|
    return if yield i
    skip!    
  end
end

#templates_for(klass_or_obj) ⇒ Array

Returns a list of templates for a certain object or class. Raises an exception if the class can’t be found in the config.

Parameters:

  • klass_or_obj (Class, Object)

    The instance / class to get the templates for.

Returns:

  • (Array)

    An array with template names



261
262
263
264
# File 'lib/skyline/rendering/renderer.rb', line 261

def templates_for(klass_or_obj)
  klass = klass_or_obj.kind_of?(Class) ? klass_or_obj : klass_or_obj.class
  self.config[klass.name].andand[:templates] || []
end