locomotivecms_search 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 322fa8e2aa6552b81a40320ac49becc17d6698ce9cb0a689ecca0671a00b95f9
4
+ data.tar.gz: aeb31eb4295cb698dd7dc3e78618cb8be1143ef31cbb36ac75972002e32f6a12
5
+ SHA512:
6
+ metadata.gz: ab385d6593d2c96ef9b972c7acdcbc5281aa8228ea3e62f41b45163ba3274fa9fa9d0c8516c5667a78dc59ace41ddcf3f5551a9cd55bdc7cbe383c9063b216a7
7
+ data.tar.gz: 1bc33531693a5e874db99953006e143412163e80094633cd6944ac5a072a1805c9020b3e77d213903d202fbb67a2354bc35edb9c8b96f03bb530480c1e5cf596
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2018, NoCoffee.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,74 @@
1
+ # Locomotive Search
2
+
3
+ Locomotive Search is an add-on for Locomotive Engine enhancing it by indexing the content of any site.
4
+
5
+ For now, only [Algolia](https://www.algolia.com) is supported.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your Rails app's Gemfile powering Locomotive Engine.
10
+
11
+ ```ruby
12
+ gem 'locomotivecms_search'
13
+ ```
14
+
15
+ And then execute:
16
+ ```bash
17
+ $ bundle
18
+ ```
19
+
20
+ Open your `config/application.rb` file of your Rails app and assign a backend like this:
21
+
22
+ ```ruby
23
+ class MyApplication < Rails::Application
24
+ ...
25
+ config.x.locomotive_search_backend = :algolia
26
+ ...
27
+ end
28
+ ```
29
+
30
+ For a smooth user experience, any modification to a page or a content entry will trigger asynchronously the indexing of the related content. Behind the scene, we use Rails ActiveJob in order to process it asynchronously. Check out the [ActiveJob documentation](http://guides.rubyonrails.org/active_job_basics.html) to set it up.
31
+
32
+ However, if you don't mind about the performance (or for testing purpose), you can "disable" ActiveJob by adding `config.active_job.queue_adapter = :inline` to your application.rb file.
33
+
34
+ ## Available backends
35
+
36
+ ### Algolia
37
+
38
+ Each Locomotive site has to set the credentials required to access the Algolia API. This can be done by adding a new metafield namespace named `algolia` in the Wagon source of the site.
39
+
40
+ In the `config/metafields_schema.yaml` file, add the following lines:
41
+
42
+ ```yaml
43
+ algolia:
44
+ label: Algolia settings
45
+ fields:
46
+ application_id:
47
+ type: string
48
+ api_key:
49
+ type: string
50
+ reset:
51
+ type: boolean
52
+ hint: 'If switched on and after pressed the save button, re-index the content of the site '
53
+ ```
54
+
55
+ Then, deploy your site and open the back-office of your Locomotive site. Go to the "Settings" section and fill in the `application_id` and `api_key` fields within the Algolia tab.
56
+
57
+ If you want to force the re-indexing all of the content of the site, toggle on the `reset` field and save the site. This procedure will start by deleting all the existing Algolia indices.
58
+
59
+ ## How to contribute
60
+
61
+ Locomotive is an open source project, we encourage contributions. If you have found a bug and want to contribute a fix, or have a new feature you would like to add, follow the steps below to get your patch into the project:
62
+
63
+ - Install ruby, mongoDB
64
+ - Clone the project <code>git clone git@github.com:locomotivecms/search.git</code>
65
+ - Start mongodb if it is not already running
66
+ - Create an Algolia account
67
+ - Set the following env variables based on your Algolia account: `ALGOLIA_APPLICATION_ID` and `ALGOLIA_API_KEY` (or add a new file named .env.test at the root of the project)
68
+ - Run the tests <code>bundle exec rspec</code>
69
+ - Write your failing tests
70
+ - Make the tests pass
71
+ - [Create a GitHub pull request](http://help.github.com/send-pull-requests)
72
+
73
+ ## License
74
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,19 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Search'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ load 'rails/tasks/statistics.rake'
18
+
19
+ require 'bundler/gem_tasks'
@@ -0,0 +1,5 @@
1
+ Locomotive::ContentEntry.class_eval do
2
+ include Locomotive::Concerns::Search
3
+ include Locomotive::Concerns::ContentEntry::IndexContent
4
+ end
5
+
@@ -0,0 +1,5 @@
1
+ Locomotive::Page.class_eval do
2
+ include Locomotive::Concerns::Search
3
+ include Locomotive::Concerns::Page::IndexContent
4
+ end
5
+
@@ -0,0 +1,4 @@
1
+ Locomotive::Site.class_eval do
2
+ include Locomotive::Concerns::Site::BuildIndices
3
+ end
4
+
@@ -0,0 +1,37 @@
1
+ module Locomotive
2
+
3
+ class BaseSearchJob < ApplicationJob
4
+
5
+ queue_as :search
6
+
7
+ protected
8
+
9
+ def search_backend(site, locale)
10
+ Rails.configuration.x.locomotive_search_backend.create(site, locale)
11
+ end
12
+
13
+ def index_page(site, page, locale)
14
+ search_backend(site, locale)&.save_object(
15
+ type: 'page',
16
+ object_id: page._id.to_s,
17
+ title: page.title,
18
+ content: page.content_to_index,
19
+ visible: page.published?,
20
+ data: page.data_to_index
21
+ )
22
+ end
23
+
24
+ def index_content_entry(site, entry, locale)
25
+ search_backend(entry.site, locale)&.save_object(
26
+ type: entry.content_type.slug,
27
+ object_id: entry._id.to_s,
28
+ title: entry._label,
29
+ content: entry.content_to_index,
30
+ visible: entry.visible?,
31
+ data: entry.data_to_index
32
+ )
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,18 @@
1
+ module Locomotive
2
+
3
+ class SearchDeleteContentEntryIndexJob < BaseSearchJob
4
+
5
+ def perform(entry_id, locale)
6
+ ::Mongoid::Fields::I18n.with_locale(locale) do
7
+ entry = Locomotive::ContentEntry.find(entry_id)
8
+
9
+ search_backend(entry.site, locale)&.delete_object(
10
+ entry.content_type.slug,
11
+ entry_id
12
+ )
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,15 @@
1
+ module Locomotive
2
+
3
+ class SearchDeletePageIndexJob < BaseSearchJob
4
+
5
+ def perform(page_id, locale)
6
+ ::Mongoid::Fields::I18n.with_locale(locale) do
7
+ page = Locomotive::Page.find(page_id)
8
+
9
+ search_backend(page.site, locale)&.delete_object('page', page_id)
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ module Locomotive
2
+
3
+ class SearchIndexContentEntryJob < BaseSearchJob
4
+
5
+ def perform(entry_id, locale)
6
+ ::Mongoid::Fields::I18n.with_locale(locale) do
7
+ entry = Locomotive::ContentEntry.find(entry_id)
8
+
9
+ index_content_entry(entry.site, entry, locale)
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ module Locomotive
2
+
3
+ class SearchIndexPageJob < BaseSearchJob
4
+
5
+ def perform(page_id, locale)
6
+ ::Mongoid::Fields::I18n.with_locale(locale) do
7
+ page = Locomotive::Page.find(page_id)
8
+
9
+ index_page(page.site, page, locale)
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,31 @@
1
+ module Locomotive
2
+
3
+ class SearchIndexSiteJob < BaseSearchJob
4
+
5
+ def perform(site_id)
6
+ site = Locomotive::Site.find(site_id)
7
+
8
+ # first remove all the indices for this site
9
+ search_backend(site, nil)&.clear_all_indices
10
+
11
+ # index the content in each locale
12
+ site.each_locale do |locale|
13
+ # index all the pages (except the 404 one)
14
+ site.pages.each do |page|
15
+ next if page.not_found?
16
+ index_page(site, page, locale)
17
+ end
18
+
19
+ # index all the content entries
20
+ site.content_types.each do |content_type|
21
+ content_type.entries.each do |entry|
22
+ index_content_entry(site, entry, locale)
23
+ end
24
+ end
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,63 @@
1
+ module Locomotive
2
+ module Concerns
3
+ module ContentEntry
4
+
5
+ module IndexContent
6
+
7
+ def content_to_index
8
+ self.custom_fields_basic_attributes.map do |(name, value)|
9
+ _name = name.gsub(/_id$/, '').gsub(/_url$/, '')
10
+
11
+ next if !value.is_a?(String) ||
12
+ name == _label_field_name.to_s || # no need to index the label (already searchable)
13
+ self.file_custom_fields.include?(_name)
14
+
15
+ sanitize_search_content(value)
16
+ end.compact.join(' ')
17
+ end
18
+
19
+ def data_to_index(parent = false)
20
+ data = default_data_to_index
21
+
22
+ data.merge!(self.custom_fields_basic_attributes) unless parent
23
+
24
+ # we also index the belongs_to relationships but we only keep
25
+ # the most important data: _label, _slug, _content_type and
26
+ # potentially their own belongs_to relationships (recursive)
27
+ self.belongs_to_custom_fields.each do |name|
28
+ data[name] = send(name.to_sym)&.data_to_index(true)
29
+ end
30
+
31
+ data
32
+ end
33
+
34
+ private
35
+
36
+ def index_content
37
+ Locomotive::SearchIndexContentEntryJob.perform_later(
38
+ self._id.to_s,
39
+ ::Mongoid::Fields::I18n.locale.to_s
40
+ )
41
+ end
42
+
43
+ def unindex_content
44
+ Locomotive::SearchDeleteContentEntryIndexJob.perform_later(
45
+ self._id.to_s,
46
+ ::Mongoid::Fields::I18n.locale.to_s
47
+ )
48
+ end
49
+
50
+ def default_data_to_index
51
+ {
52
+ '_content_type' => self.content_type.slug,
53
+ '_slug' => self._slug,
54
+ '_label' => self._label
55
+ }
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,50 @@
1
+ module Locomotive
2
+ module Concerns
3
+ module Page
4
+
5
+ module IndexContent
6
+
7
+ def content_to_index
8
+ self.editable_elements.where(_type: 'Locomotive::EditableText').map do |element|
9
+ sanitize_search_content(element.content)
10
+ end.join(' ')
11
+ end
12
+
13
+ def data_to_index
14
+ {
15
+ title: self.title,
16
+ slug: self.slug,
17
+ fullpath: self.fullpath
18
+ }
19
+ end
20
+
21
+ private
22
+
23
+ def index_content
24
+ # don't index the 404 error page
25
+ return if self.not_found?
26
+
27
+ # don't block the server app
28
+ Locomotive::SearchIndexPageJob.perform_later(
29
+ self._id.to_s,
30
+ ::Mongoid::Fields::I18n.locale.to_s
31
+ )
32
+ end
33
+
34
+ def unindex_content
35
+ # don't index the 404 error page
36
+ return if self.not_found?
37
+
38
+ # don't block the server app
39
+ Locomotive::SearchDeletePageIndexJob.perform_later(
40
+ self._id.to_s,
41
+ ::Mongoid::Fields::I18n.locale.to_s
42
+ )
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,26 @@
1
+ module Locomotive
2
+ module Concerns
3
+ module Search
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+
9
+ after_save :index_content, if: :search_enabled?
10
+ after_destroy :unindex_content, if: :search_enabled?
11
+
12
+ end
13
+
14
+ private
15
+
16
+ def search_enabled?
17
+ Rails.configuration.x.locomotive_search_backend.enabled_for?(self.site)
18
+ end
19
+
20
+ def sanitize_search_content(text)
21
+ ::ActionController::Base.helpers.strip_tags(text)
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,43 @@
1
+ module Locomotive
2
+ module Concerns
3
+ module Site
4
+
5
+ module BuildIndices
6
+
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+
11
+ after_validation :check_for_building_search_indices
12
+ before_save :search_reset_done!, if: :building_search_indices?
13
+ after_save :build_search_indices, if: :building_search_indices?
14
+
15
+ end
16
+
17
+ private
18
+
19
+ def building_search_indices?
20
+ !!@building_search_indices
21
+ end
22
+
23
+ def check_for_building_search_indices
24
+ @building_search_indices = search_reset?
25
+ end
26
+
27
+ def build_search_indices
28
+ Locomotive::SearchIndexSiteJob.perform_later(self._id.to_s)
29
+ end
30
+
31
+ def search_reset?
32
+ Rails.configuration.x.locomotive_search_backend.reset_for?(self)
33
+ end
34
+
35
+ def search_reset_done!
36
+ Rails.configuration.x.locomotive_search_backend.reset_done!(self)
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,89 @@
1
+ require 'algoliasearch'
2
+
3
+ module Locomotive
4
+ module Search
5
+ module Backend
6
+
7
+ class Algolia
8
+
9
+ attr :site, :locale, :client
10
+
11
+ def initialize(site, locale)
12
+ @site, @locale = site, locale
13
+
14
+ if site.metafields['algolia']
15
+ credentials = site.metafields['algolia'].slice('application_id', 'api_key').symbolize_keys
16
+ @client = ::Algolia::Client.new(credentials)
17
+ end
18
+ end
19
+
20
+ # Add the object to 2 indices:
21
+ # - global: in order to perform a global search among all the entities: page, content entries
22
+ # - object: in order to perform a local search among the pages or a content type
23
+ #
24
+ # Names of the indices:
25
+ # - global: locomotive-<Rails env>-<site handle>-<locale>
26
+ # - object: locomotive-<Rails env>-<site handle>-<locale>-<type: page or a content type>
27
+ #
28
+ def save_object(type: nil, object_id: nil, title: nil, content: nil, visible: true, data: {})
29
+ base_object = { objectID: object_id, visible: visible, type: type }
30
+ object = { title: title, content: content, data: data }.merge(base_object)
31
+
32
+ object_index(type).save_objects([data.merge(base_object)])
33
+ global_index.save_objects([object])
34
+ end
35
+
36
+ def delete_object(type, object_id)
37
+ object_type_index(type).delete_object(object_id)
38
+ global_index.delete_object(object_id)
39
+ end
40
+
41
+ def clear_all_indices
42
+ client.list_indexes['items'].each do |index_attributes|
43
+ name = index_attributes['name']
44
+
45
+ next unless name =~ /^#{self.base_index_name}-/
46
+
47
+ ::Algolia::Index.new(name, self.client).clear_index
48
+ end
49
+ end
50
+
51
+ def valid?
52
+ @client.present?
53
+ end
54
+
55
+ def global_index
56
+ name = [base_index_name, self.locale].join('-')
57
+ ::Algolia::Index.new(name, self.client)
58
+ end
59
+
60
+ def object_index(type)
61
+ name = [base_index_name, self.locale, type].join('-')
62
+ ::Algolia::Index.new(name, self.client)
63
+ end
64
+
65
+ def base_index_name
66
+ ['locomotive', Rails.env, self.site.handle].join('-')
67
+ end
68
+
69
+ def self.enabled_for?(site)
70
+ site.metafields.present? &&
71
+ site.metafields['algolia'].present? &&
72
+ site.metafields['algolia']['application_id'].present? &&
73
+ site.metafields['algolia']['api_key'].present?
74
+ end
75
+
76
+ def self.reset_for?(site)
77
+ enabled_for?(site) &&
78
+ [1, '1', true].include?(site.metafields['algolia']['reset'])
79
+ end
80
+
81
+ def self.reset_done!(site)
82
+ site.metafields['algolia']['reset'] = false
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,52 @@
1
+ module Locomotive
2
+ module Search
3
+
4
+ class BackendFactory
5
+
6
+ attr_reader :klass
7
+
8
+ def initialize(name_or_klass)
9
+ if name_or_klass.is_a?(Symbol) || name_or_klass.is_a?(String)
10
+ begin
11
+ require_relative "./backend/#{name_or_klass}"
12
+ @klass = "Locomotive::Search::Backend::#{name_or_klass.to_s.camelize}".constantize
13
+ rescue LoadError
14
+ raise UnknownBackendError.new("'#{name_or_klass}' is not a valid backend")
15
+ end
16
+ else
17
+ @klass = name_or_klass
18
+ end
19
+ end
20
+
21
+ def create(site, locale)
22
+ return nil unless self.setup?
23
+
24
+ backend = self.klass.new(site, locale)
25
+ backend.valid? ? backend : nil
26
+ end
27
+
28
+ def name
29
+ return nil unless self.setup?
30
+
31
+ self.klass.name.demodulize.underscore
32
+ end
33
+
34
+ def setup?
35
+ self.klass.present?
36
+ end
37
+
38
+ def enabled_for?(site)
39
+ self.setup? && self.klass.enabled_for?(site)
40
+ end
41
+
42
+ def reset_for?(site)
43
+ self.setup? && self.klass.reset_for?(site)
44
+ end
45
+
46
+ def reset_done!(site)
47
+ self.setup? && self.klass.reset_done!(site)
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,21 @@
1
+ module Locomotive
2
+ module Search
3
+ class Engine < ::Rails::Engine
4
+
5
+ initializer 'locomotive.search.backend' do |app|
6
+ if backend_name = app.config.x.locomotive_search_backend
7
+ app.config.x.locomotive_search_backend = BackendFactory.new(backend_name)
8
+ end
9
+ end
10
+
11
+ # Allow the pkugin to change the behavior of Locomotive controllers and
12
+ # models in a clean way.
13
+ config.to_prepare do
14
+ Dir.glob(Engine.root + 'app/decorators/**/*_decorator*.rb').each do |c|
15
+ require_dependency(c)
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ module Locomotive::Search
2
+
3
+ class UnknownBackendError < StandardError; end
4
+
5
+ end
@@ -0,0 +1,5 @@
1
+ module Locomotive
2
+ module Search
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ require 'locomotive/search/errors'
2
+ require 'locomotive/search/backend_factory'
3
+ require 'locomotive/search/engine'
4
+
5
+ module Locomotive::Search
6
+ # Your code goes here...
7
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :search do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: locomotivecms_search
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Didier Lafforgue
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-04-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.1.6
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '6'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 5.1.6
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '6'
33
+ - !ruby/object:Gem::Dependency
34
+ name: algoliasearch
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.19'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.19'
47
+ description: 'The LocomotiveCMS search automatically indexes the content of each site.
48
+ Search engine supported: Algolia'
49
+ email:
50
+ - didier@nocoffee.fr
51
+ executables: []
52
+ extensions: []
53
+ extra_rdoc_files: []
54
+ files:
55
+ - MIT-LICENSE
56
+ - README.md
57
+ - Rakefile
58
+ - app/decorators/locomotive/content_entry_decorator.rb
59
+ - app/decorators/locomotive/page_decorator.rb
60
+ - app/decorators/locomotive/site_decorator.rb
61
+ - app/jobs/locomotive/base_search_job.rb
62
+ - app/jobs/locomotive/search_delete_content_entry_index_job.rb
63
+ - app/jobs/locomotive/search_delete_page_index_job.rb
64
+ - app/jobs/locomotive/search_index_content_entry_job.rb
65
+ - app/jobs/locomotive/search_index_page_job.rb
66
+ - app/jobs/locomotive/search_index_site_job.rb
67
+ - app/models/locomotive/concerns/content_entry/index_content.rb
68
+ - app/models/locomotive/concerns/page/index_content.rb
69
+ - app/models/locomotive/concerns/search.rb
70
+ - app/models/locomotive/concerns/site/build_indices.rb
71
+ - lib/locomotive/search/backend/algolia.rb
72
+ - lib/locomotive/search/backend_factory.rb
73
+ - lib/locomotive/search/engine.rb
74
+ - lib/locomotive/search/errors.rb
75
+ - lib/locomotive/search/version.rb
76
+ - lib/locomotivecms_search.rb
77
+ - lib/tasks/locomotive/search_tasks.rake
78
+ homepage: https://www.locomotivecms.com
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.7.3
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: The LocomotiveCMS search enables advanced search functionalities for each
102
+ site
103
+ test_files: []