class Middleman::Sitemap::SearchIndexResource

Public Class Methods

new(store, path, options) click to toggle source
Calls superclass method
# File lib/middleman-search/search-index-resource.rb, line 6
def initialize(store, path, options)
  @resources_to_index = options[:resources]
  @fields = options[:fields]
  @callback = options[:before_index]
  @pipeline = options[:pipeline]
  @cache_index = options[:cache]
  @language = options[:language]
  @lunr_dirs = options[:lunr_dirs] + [File.expand_path("../../../vendor/assets/javascripts/", __FILE__)]
  super(store, path)
end

Public Instance Methods

binary?() click to toggle source
# File lib/middleman-search/search-index-resource.rb, line 110
def binary?
  false
end
build_index() click to toggle source
# File lib/middleman-search/search-index-resource.rb, line 33
def build_index
  # Build js context
  context = V8::Context.new
  context.load(lunr_resource('lunr.js'))

  if @language != 'en' # English is the default
    context.load(lunr_resource("lunr.stemmer.support.js"))
    context.load(lunr_resource("lunr.#{@language}.js"))
    lunr_lang = context.eval("lunr.#{@language}")
  end

  context.eval('lunr.Index.prototype.indexJson = function () {return JSON.stringify(this.toJSON());}')

  # Register pipeline functions
  pipeline = context.eval('lunr.Pipeline')
  @pipeline.each do |name, function|
    context[name] = context.eval("(#{function})")
    pipeline.registerFunction(context[name], name)
  end

  # Build lunr based on config
  lunr = context.eval('lunr')
  lunr_conf = proc do |this|

    # Use autogenerated id field as reference
    this.ref('id')

    # Add functions to pipeline (just registering them isn't enough)
    @pipeline.each do |name, function|
      this.pipeline.add(context[name])
    end

    # Define fields with boost
    this.use(lunr_lang) if @language != 'en'
    @fields.each do |field, opts|
      next if opts[:index] == false
      this.field(field, {:boost => opts[:boost]})
    end
  end

  # Get lunr index
  index = lunr.call(lunr_conf)

  # Ref to resource map
  store = Hash.new

  # Iterate over all resources and build index
  @app.sitemap.resources.each_with_index do |resource, id|
    begin
      catch(:skip) do
        next if resource.data['index'] == false
        next unless @resources_to_index.any? {|whitelisted| resource.path.start_with? whitelisted }

        to_index = Hash.new
        to_store = Hash.new

        @fields.each do |field, opts|
          value = value_for(resource, field, opts)
          throw(:skip) if value.blank? && opts[:required]
          to_index[field] = value unless opts[:index] == false
          to_store[field] = value if opts[:store]
        end

        @callback.call(to_index, to_store, resource) if @callback

        index.add(to_index.merge(id: id))
        store[id] = to_store
      end
    rescue => ex
      @app.logger.warn "Error processing resource for index: #{resource.path}\n#{ex}\n #{ex.backtrace.join("\n ")}"
    end
  end

  # Generate JSON output
  "{\"index\": #{index.indexJson()}, \"docs\": #{store.to_json}}"
end
get_source_file() click to toggle source
# File lib/middleman-search/search-index-resource.rb, line 21
def get_source_file
  path
end
ignored?() click to toggle source
# File lib/middleman-search/search-index-resource.rb, line 114
def ignored?
  false
end
render(opts={}, locs={}) click to toggle source
# File lib/middleman-search/search-index-resource.rb, line 25
def render(opts={}, locs={})
  if @cache_index
    @index ||= build_index
  else
    build_index
  end
end
template?() click to toggle source
# File lib/middleman-search/search-index-resource.rb, line 17
def template?
  false
end
value_for(resource, field, opts={}) click to toggle source
# File lib/middleman-search/search-index-resource.rb, line 118
def value_for(resource, field, opts={})
  case field.to_s
  when 'content'

    html = resource.render( { :layout => false }, { :current_path => resource.path } )
    Nokogiri::HTML(html).xpath("//text()").text
  when 'url'
    resource.url
  else
    value = resource.data.send(field) || resource.metadata.fetch(:options, {}).fetch(field, nil)
    value ? Array(value).compact.join(" ") : nil
  end
end

Private Instance Methods

lunr_resource(resource_name) click to toggle source
# File lib/middleman-search/search-index-resource.rb, line 140
def lunr_resource(resource_name)
  @lunr_dirs.flat_map do |dir|
    [File.join(dir, minified_path(resource_name)), File.join(dir, resource_name)]
  end.detect { |file| File.exists? file } or raise "Couldn't find #{resource_name} nor #{minified_path(resource_name)} in #{@lunr_dirs.map {|dir| File.absolute_path dir }.join File::PATH_SEPARATOR}"
end
minified_path(resource_name) click to toggle source
# File lib/middleman-search/search-index-resource.rb, line 134
def minified_path(resource_name)
  return resource_name if resource_name.end_with? '.min.js'
  return resource_name unless resource_name.end_with? '.js'
  resource_name.sub(/(.*)\.js$/,'\1.min.js')
end