middleman-search 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +56 -10
- data/lib/middleman-search/extension.rb +11 -1
- data/lib/middleman-search/search-index-resource.rb +20 -1
- data/lib/middleman-search/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3dc491d945d930fbca061b6e1c93fa4d2f5b2d1e
|
4
|
+
data.tar.gz: 63d5f6e7adbe105b1a865f631c8b365151381951
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba2d93142dda2dbae2736566e81e5d97e77a05c1fa5ac9acec09a8bf7f37764f2d1e720af4084d0aa980cab197049a32e4ae36c2c8ce83d38c7f23e0f42e2e37
|
7
|
+
data.tar.gz: a16b4903505af7c62a79d0936cf09296e211fba49dc6e4557465deb275b8e5f91dac8b306e3555ce3f03e184260d54a1b8cb487e3ead12f841981e09038836a4
|
data/README.md
CHANGED
@@ -22,19 +22,17 @@ You need to activate the module in your `config.rb`, telling the extension how t
|
|
22
22
|
|
23
23
|
```ruby
|
24
24
|
activate :search do
|
25
|
+
|
25
26
|
search.resources = ['blog/', 'index.html', 'contactus/index.html']
|
27
|
+
|
26
28
|
search.index_path = 'search/lunr-index.json' # defaults to `search.json`
|
29
|
+
|
27
30
|
search.fields = {
|
28
31
|
title: {boost: 100, store: true, required: true},
|
29
32
|
content: {boost: 50},
|
30
33
|
url: {index: false, store: true},
|
31
34
|
author: {boost: 30}
|
32
35
|
}
|
33
|
-
search.before_index = Proc.new do |to_index, to_store, resource|
|
34
|
-
if author = resource.data.author
|
35
|
-
to_index[:author] = data.authors[author].name
|
36
|
-
end
|
37
|
-
end
|
38
36
|
end
|
39
37
|
```
|
40
38
|
|
@@ -47,18 +45,59 @@ Where `resources` is a list of the beginning of the URL of the resources to inde
|
|
47
45
|
|
48
46
|
Note that a special field `id` is included automatically, with an autogenerated identifier to be used as the `ref` for the document.
|
49
47
|
|
50
|
-
All fields values are retrieved from the resource `data` (
|
48
|
+
All fields values are retrieved from the resource `data` (i.e. its frontmatter), or from the `options` in the `resource.metadata` (i.e. any options specified in a `proxy` page), except for:
|
51
49
|
- `url` which is the actual resource url
|
52
50
|
- `content` the text extracted from the rendered resource, without including its layout
|
53
51
|
|
54
|
-
|
52
|
+
### Manual index manipulation
|
55
53
|
|
56
|
-
You
|
54
|
+
You can fully customise the content to be indexed and stored per resource by defining a `before_index` callback:
|
57
55
|
|
58
|
-
```
|
59
|
-
|
56
|
+
```ruby
|
57
|
+
activate :search do
|
58
|
+
search.before_index = Proc.new do |to_index, to_store, resource|
|
59
|
+
if author = resource.data.author
|
60
|
+
to_index[:author] = data.authors[author].name
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
This option accepts a callback that will be executed for each resource, and will be executed with the document to be indexed and the map to be stored, in the `index` and `docs` objects of the output respectively (see below), as well as the resource being processed. You can use this callback to modify either of those, or `throw(:skip)` to skip the resource in question.
|
67
|
+
|
68
|
+
### Lunr pipeline configuration
|
69
|
+
|
70
|
+
In some cases, you may want to add new function to the lunr pipeline, both for creating the indexing and then for searching. You can do this by providing a `pipeline` hash with function names and body, for example:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
activate :search do
|
74
|
+
search.pipeline = {
|
75
|
+
tildes: <<-JS
|
76
|
+
function(token, tokenIndex, tokens) {
|
77
|
+
return token
|
78
|
+
.replace('á', 'a')
|
79
|
+
.replace('é', 'e')
|
80
|
+
.replace('í', 'i')
|
81
|
+
.replace('ó', 'o')
|
82
|
+
.replace('ú', 'u');
|
83
|
+
}
|
84
|
+
JS
|
85
|
+
}
|
86
|
+
end
|
60
87
|
```
|
61
88
|
|
89
|
+
This will register the `tildes` function in the lunr pipeline and add it when building the index. From the Lunr documentation:
|
90
|
+
|
91
|
+
> Functions in the pipeline are called with three arguments: the current token being processed; the index of that token in the array of tokens, and the whole list of tokens part of the document being processed. This enables simple unigram processing of tokens as well as more sophisticated n-gram processing.
|
92
|
+
>
|
93
|
+
> The function should return the processed version of the text, which will in turn be passed to the next function in the pipeline. Returning undefined will prevent any further processing of the token, and that token will not make it to the index.
|
94
|
+
|
95
|
+
Note that if you add a function to the pipeline, it will also be loaded when de-serialising the index, and lunr will fail with an `Cannot load un-registered function: tildes` error if it has not been re-registered. You can either register them manually, or simply include the following in a `.js.erb` file to be executed __before__ loading the index:
|
96
|
+
```erb
|
97
|
+
<%= lunr_js_pipeline %>
|
98
|
+
```
|
99
|
+
|
100
|
+
|
62
101
|
## Index file
|
63
102
|
|
64
103
|
The generated index file contains a JSON object with two properties:
|
@@ -67,6 +106,13 @@ The generated index file contains a JSON object with two properties:
|
|
67
106
|
|
68
107
|
You will typically load the `index` into a lunr index instance, and then use the `docs` map to look up the returned value and present it to the user.
|
69
108
|
|
109
|
+
You should also `require` the `lunr.min.js` file in your main sprockets javascript file to be able to actually load the index:
|
110
|
+
|
111
|
+
```javascript
|
112
|
+
//= require lunr.min
|
113
|
+
```
|
114
|
+
|
115
|
+
|
70
116
|
## Acknowledgments
|
71
117
|
|
72
118
|
A big thank you to:
|
@@ -5,12 +5,22 @@ module Middleman
|
|
5
5
|
class SearchExtension < Middleman::Extension
|
6
6
|
option :resources, [], 'Paths of resources to index'
|
7
7
|
option :fields, {}, 'Fields to index, with their options'
|
8
|
-
option :before_index, nil, 'Callback
|
8
|
+
option :before_index, nil, 'Callback to execute before indexing a document'
|
9
9
|
option :index_path, 'search.json', 'Index file path'
|
10
|
+
option :pipeline, {}, 'Javascript pipeline functions to use in lunr index'
|
10
11
|
|
11
12
|
def manipulate_resource_list(resources)
|
12
13
|
resources.push Middleman::Sitemap::SearchIndexResource.new(@app.sitemap, @options[:index_path], @options)
|
13
14
|
resources
|
14
15
|
end
|
16
|
+
|
17
|
+
helpers do
|
18
|
+
def lunr_js_pipeline
|
19
|
+
# Thanks http://stackoverflow.com/a/20187415/12791
|
20
|
+
extensions[:search].options[:pipeline].map do |name, function|
|
21
|
+
"lunr.Pipeline.registerFunction(#{function}, '#{name}');"
|
22
|
+
end.join("\n")
|
23
|
+
end
|
24
|
+
end
|
15
25
|
end
|
16
26
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
module Middleman
|
2
4
|
module Sitemap
|
3
5
|
class SearchIndexResource < ::Middleman::Sitemap::Resource
|
@@ -5,6 +7,7 @@ module Middleman
|
|
5
7
|
@resources_to_index = options[:resources]
|
6
8
|
@fields = options[:fields]
|
7
9
|
@callback = options[:before_index]
|
10
|
+
@pipeline = options[:pipeline]
|
8
11
|
super(store, path)
|
9
12
|
end
|
10
13
|
|
@@ -20,12 +23,28 @@ module Middleman
|
|
20
23
|
# Build js context
|
21
24
|
context = V8::Context.new
|
22
25
|
context.load(File.expand_path('../../../vendor/assets/javascripts/lunr.min.js', __FILE__))
|
23
|
-
context.eval('lunr.Index.prototype.indexJson = function () {return JSON.stringify(this);}')
|
26
|
+
context.eval('lunr.Index.prototype.indexJson = function () {return JSON.stringify(this.toJSON());}')
|
27
|
+
|
28
|
+
# Register pipeline functions
|
29
|
+
pipeline = context.eval('lunr.Pipeline')
|
30
|
+
@pipeline.each do |name, function|
|
31
|
+
context[name] = context.eval("(#{function})")
|
32
|
+
pipeline.registerFunction(context[name], name)
|
33
|
+
end
|
24
34
|
|
25
35
|
# Build lunr based on config
|
26
36
|
lunr = context.eval('lunr')
|
27
37
|
lunr_conf = proc do |this|
|
38
|
+
|
39
|
+
# Use autogenerated id field as reference
|
28
40
|
this.ref('id')
|
41
|
+
|
42
|
+
# Add functions to pipeline (just registering them isn't enough)
|
43
|
+
@pipeline.each do |name, function|
|
44
|
+
this.pipeline.add(context[name])
|
45
|
+
end
|
46
|
+
|
47
|
+
# Define fields with boost
|
29
48
|
@fields.each do |field, opts|
|
30
49
|
next if opts[:index] == false
|
31
50
|
this.field(field, {:boost => opts[:boost]})
|