action_policy 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e593d4567bab1e7fec960db2d67d7d659d4b4df92159741b7db715b35b75c790
4
- data.tar.gz: efdc9d9815936a6dcbb0e94b0098050bc30fddae20a3d06f35bf03b91787d500
3
+ metadata.gz: 998666ad64277112c6ddc44e6db9e0aa81b6bbf32994fb675797bcd8e1f9ca70
4
+ data.tar.gz: 5a35c722589841c6b41d6efd1735abe63833db03b9a7aec23e798648a97c5470
5
5
  SHA512:
6
- metadata.gz: c58c58e14c25f4daadc890ab67de43781f33f28485811b05458568b9003b9037911fbaade9332dca0b458dec811138df87fa094564574cd55fae948a09379be8
7
- data.tar.gz: 12db66ef181fa94ec6ac2c48feeb7fe49d12a3b66a9a554c925594b9b622ec3cec94412e48db13406d71733d0ae001f7dece5fedfe56ca11216f6e027754765f
6
+ metadata.gz: 03a5594069a5947566708f3b3ad419d79be8931d38c25195f754d1474fa9b2f3bcf5e0f9e520a828d56c1fcfac762929ae4fdcf852c657f4b6bec973c0559e0b
7
+ data.tar.gz: e41e88d916fdf0832e7b03cdadcf7f6c1a4814c45e6ca76e12094bbcb03a6ea54146a0e676d079a0813caff31f54c3dfe90d0e917ade8c4261e17ec4d55a4221
@@ -1,5 +1,11 @@
1
1
  ## master
2
2
 
3
+ ## 0.3.2 (2019-05-26) 👶
4
+
5
+ - Fixed thread-safety issues with scoping configs. ([@palkan][])
6
+
7
+ Fixes [#75](https://github.com/palkan/action_policy/issues/75).
8
+
3
9
  ## 0.3.1 (2019-05-30)
4
10
 
5
11
  - Fixed bug with missing implicit target and hash like scoping data. ([@palkan][])
data/README.md CHANGED
@@ -4,7 +4,9 @@
4
4
 
5
5
  # ActionPolicy
6
6
 
7
- Action Policy is an authorization framework for Ruby and Rails applications.
7
+ Authorization framework for Ruby and Rails applications.
8
+
9
+ Composable. Extensible. Performant.
8
10
 
9
11
  📑 [Documentation](https://actionpolicy.evilmartians.io)
10
12
 
@@ -3,7 +3,8 @@
3
3
 
4
4
  ## Action Policy
5
5
 
6
- > Action Policy is an authorization framework for Ruby and Rails applications.
6
+ > Authorization framework for Ruby and Rails.
7
+ <br>Composable. Extensible. Performant.
7
8
 
8
9
  **NOTE:** this documentation is for the version "0.3.0+".
9
10
 
@@ -20,6 +21,12 @@ Action Policy provides flexible tools to build an _authorization layer_ for your
20
21
 
21
22
  **NOTE:** Action Policy does not force you to use a specific authorization model (i.e., roles, permissions, etc.) and does not provide one. It only answers a single question: **How to verify access?**
22
23
 
24
+ ## Where to go from here?
25
+ - [Quick start](./quick_start.md)
26
+ - [Using with Rails](./rails.md)
27
+ - [Using with other Ruby frameworks](./non_rails.md)
28
+ - [Using with GraphQL Ruby](./graphql.md)
29
+
23
30
  ## Project State
24
31
 
25
32
  The project is being used in production since mid 2018. Major features have been implemented, API has been stabilized. Check out our [development board](https://github.com/palkan/action_policy/projects/1) to see what's coming next.
@@ -0,0 +1,364 @@
1
+ (function () {
2
+ var INDEXS = {};
3
+
4
+ var LOCAL_STORAGE = {
5
+ EXPIRE_KEY: 'docsify.search.expires',
6
+ INDEX_KEY: 'docsify.search.index'
7
+ };
8
+
9
+ function resolveExpireKey(namespace) {
10
+ return namespace ? ((LOCAL_STORAGE.EXPIRE_KEY) + "/" + namespace) : LOCAL_STORAGE.EXPIRE_KEY
11
+ }
12
+ function resolveIndexKey(namespace) {
13
+ return namespace ? ((LOCAL_STORAGE.INDEX_KEY) + "/" + namespace) : LOCAL_STORAGE.INDEX_KEY
14
+ }
15
+
16
+ function escapeHtml(string) {
17
+ var entityMap = {
18
+ '&': '&amp;',
19
+ '<': '&lt;',
20
+ '>': '&gt;',
21
+ '"': '&quot;',
22
+ '\'': '&#39;',
23
+ '/': '&#x2F;'
24
+ };
25
+
26
+ return String(string).replace(/[&<>"'/]/g, function (s) { return entityMap[s]; })
27
+ }
28
+
29
+ function getAllPaths(router) {
30
+ var paths = [];
31
+
32
+ Docsify.dom.findAll('.sidebar-nav a:not(.section-link):not([data-nosearch])').forEach(function (node) {
33
+ var href = node.href;
34
+ var originHref = node.getAttribute('href');
35
+ var path = router.parse(href).path;
36
+
37
+ if (
38
+ path &&
39
+ paths.indexOf(path) === -1 &&
40
+ !Docsify.util.isAbsolutePath(originHref)
41
+ ) {
42
+ paths.push(path);
43
+ }
44
+ });
45
+
46
+ return paths
47
+ }
48
+
49
+ function saveData(maxAge, expireKey, indexKey) {
50
+ localStorage.setItem(expireKey, Date.now() + maxAge);
51
+ localStorage.setItem(indexKey, JSON.stringify(INDEXS));
52
+ }
53
+
54
+ function genIndex(path, content, router, depth) {
55
+ if ( content === void 0 ) content = '';
56
+
57
+ var tokens = window.marked.lexer(content);
58
+ var slugify = window.Docsify.slugify;
59
+ var index = {};
60
+ var slug;
61
+
62
+ tokens.forEach(function (token) {
63
+ if (token.type === 'heading' && token.depth <= depth) {
64
+ slug = router.toURL(path, {id: slugify(token.text)});
65
+ index[slug] = {slug: slug, title: token.text, body: ''};
66
+ } else {
67
+ if (!slug) {
68
+ return
69
+ }
70
+ if (!index[slug]) {
71
+ index[slug] = {slug: slug, title: '', body: ''};
72
+ } else if (index[slug].body) {
73
+ index[slug].body += '\n' + (token.text || '');
74
+ } else {
75
+ index[slug].body = token.text;
76
+ }
77
+ }
78
+ });
79
+ slugify.clear();
80
+ return index
81
+ }
82
+
83
+ /**
84
+ * @param {String} query
85
+ * @returns {Array}
86
+ */
87
+ function search(query) {
88
+ var matchingResults = [];
89
+ var data = [];
90
+ Object.keys(INDEXS).forEach(function (key) {
91
+ data = data.concat(Object.keys(INDEXS[key]).map(function (page) { return INDEXS[key][page]; }));
92
+ });
93
+
94
+ query = query.trim();
95
+ var keywords = query.split(/[\s\-,\\/]+/);
96
+ if (keywords.length !== 1) {
97
+ keywords = [].concat(query, keywords);
98
+ }
99
+
100
+ var loop = function ( i ) {
101
+ var post = data[i];
102
+ var matchesScore = 0;
103
+ var resultStr = '';
104
+ var postTitle = post.title && post.title.trim();
105
+ var postContent = post.body && post.body.trim();
106
+ var postUrl = post.slug || '';
107
+
108
+ if (postTitle) {
109
+ keywords.forEach( function (keyword) {
110
+ // From https://github.com/sindresorhus/escape-string-regexp
111
+ var regEx = new RegExp(
112
+ keyword.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'),
113
+ 'gi'
114
+ );
115
+ var indexTitle = -1;
116
+ var indexContent = -1;
117
+
118
+ indexTitle = postTitle ? postTitle.search(regEx) : -1;
119
+ indexContent = postContent ? postContent.search(regEx) : -1;
120
+
121
+ if (indexTitle >= 0 || indexContent >= 0) {
122
+ matchesScore += indexTitle >= 0 ? 3 : indexContent >= 0 ? 2 : 0;
123
+ if (indexContent < 0) {
124
+ indexContent = 0;
125
+ }
126
+
127
+ var start = 0;
128
+ var end = 0;
129
+
130
+ start = indexContent < 11 ? 0 : indexContent - 10;
131
+ end = start === 0 ? 70 : indexContent + keyword.length + 60;
132
+
133
+ if (end > postContent.length) {
134
+ end = postContent.length;
135
+ }
136
+
137
+ var matchContent =
138
+ '...' +
139
+ escapeHtml(postContent)
140
+ .substring(start, end)
141
+ .replace(regEx, ("<em class=\"search-keyword\">" + keyword + "</em>")) +
142
+ '...';
143
+
144
+ resultStr += matchContent;
145
+ }
146
+ });
147
+
148
+ if (matchesScore > 0) {
149
+ var matchingPost = {
150
+ title: escapeHtml(postTitle),
151
+ content: postContent ? resultStr : '',
152
+ url: postUrl,
153
+ score: matchesScore
154
+ };
155
+
156
+ matchingResults.push(matchingPost);
157
+ }
158
+ }
159
+ };
160
+
161
+ for (var i = 0; i < data.length; i++) loop( i );
162
+
163
+ return matchingResults.sort(function (r1, r2) { return r2.score - r1.score; });
164
+ }
165
+
166
+ function init$1(config, vm) {
167
+ var isAuto = config.paths === 'auto';
168
+
169
+ var expireKey = resolveExpireKey(config.namespace);
170
+ var indexKey = resolveIndexKey(config.namespace);
171
+
172
+ var isExpired = localStorage.getItem(expireKey) < Date.now();
173
+
174
+ INDEXS = JSON.parse(localStorage.getItem(indexKey));
175
+
176
+ if (isExpired) {
177
+ INDEXS = {};
178
+ } else if (!isAuto) {
179
+ return
180
+ }
181
+
182
+ var paths = isAuto ? getAllPaths(vm.router) : config.paths;
183
+ var len = paths.length;
184
+ var count = 0;
185
+
186
+ paths.forEach(function (path) {
187
+ if (INDEXS[path]) {
188
+ return count++
189
+ }
190
+
191
+ Docsify
192
+ .get(vm.router.getFile(path), false, vm.config.requestHeaders)
193
+ .then(function (result) {
194
+ INDEXS[path] = genIndex(path, result, vm.router, config.depth);
195
+ len === ++count && saveData(config.maxAge, expireKey, indexKey);
196
+ });
197
+ });
198
+ }
199
+
200
+ var NO_DATA_TEXT = '';
201
+ var options;
202
+
203
+ function style() {
204
+ var code = "\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0 7px;\n line-height: 36px;\n font-size: 14px;\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n.search .clear-button {\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}";
205
+
206
+ Docsify.dom.style(code);
207
+ }
208
+
209
+ function tpl(defaultValue) {
210
+ if ( defaultValue === void 0 ) defaultValue = '';
211
+
212
+ var html =
213
+ "<div class=\"input-wrap\">\n <input type=\"search\" value=\"" + defaultValue + "\" />\n <div class=\"clear-button\">\n <svg width=\"26\" height=\"24\">\n <circle cx=\"12\" cy=\"12\" r=\"11\" fill=\"#ccc\" />\n <path stroke=\"white\" stroke-width=\"2\" d=\"M8.25,8.25,15.75,15.75\" />\n <path stroke=\"white\" stroke-width=\"2\"d=\"M8.25,15.75,15.75,8.25\" />\n </svg>\n </div>\n </div>\n <div class=\"results-panel\"></div>\n </div>";
214
+ var el = Docsify.dom.create('div', html);
215
+ var aside = Docsify.dom.find('aside');
216
+
217
+ Docsify.dom.toggleClass(el, 'search');
218
+ Docsify.dom.before(aside, el);
219
+ }
220
+
221
+ function doSearch(value) {
222
+ var $search = Docsify.dom.find('div.search');
223
+ var $panel = Docsify.dom.find($search, '.results-panel');
224
+ var $clearBtn = Docsify.dom.find($search, '.clear-button');
225
+ var $sidebarNav = Docsify.dom.find('.sidebar-nav');
226
+ var $appName = Docsify.dom.find('.app-name');
227
+
228
+ if (!value) {
229
+ $panel.classList.remove('show');
230
+ $clearBtn.classList.remove('show');
231
+ $panel.innerHTML = '';
232
+
233
+ if (options.hideOtherSidebarContent) {
234
+ $sidebarNav.classList.remove('hide');
235
+ $appName.classList.remove('hide');
236
+ }
237
+ return
238
+ }
239
+ var matchs = search(value);
240
+
241
+ var html = '';
242
+ matchs.forEach(function (post) {
243
+ html += "<div class=\"matching-post\">\n<a href=\"" + (post.url) + "\">\n<h2>" + (post.title) + "</h2>\n<p>" + (post.content) + "</p>\n</a>\n</div>";
244
+ });
245
+
246
+ $panel.classList.add('show');
247
+ $clearBtn.classList.add('show');
248
+ $panel.innerHTML = html || ("<p class=\"empty\">" + NO_DATA_TEXT + "</p>");
249
+ if (options.hideOtherSidebarContent) {
250
+ $sidebarNav.classList.add('hide');
251
+ $appName.classList.add('hide');
252
+ }
253
+ }
254
+
255
+ function bindEvents() {
256
+ var $search = Docsify.dom.find('div.search');
257
+ var $input = Docsify.dom.find($search, 'input');
258
+ var $inputWrap = Docsify.dom.find($search, '.input-wrap');
259
+
260
+ var timeId;
261
+ // Prevent to Fold sidebar
262
+ Docsify.dom.on(
263
+ $search,
264
+ 'click',
265
+ function (e) { return e.target.tagName !== 'A' && e.stopPropagation(); }
266
+ );
267
+ Docsify.dom.on($input, 'input', function (e) {
268
+ clearTimeout(timeId);
269
+ timeId = setTimeout(function (_) { return doSearch(e.target.value.trim()); }, 100);
270
+ });
271
+ Docsify.dom.on($inputWrap, 'click', function (e) {
272
+ // Click input outside
273
+ if (e.target.tagName !== 'INPUT') {
274
+ $input.value = '';
275
+ doSearch();
276
+ }
277
+ });
278
+ }
279
+
280
+ function updatePlaceholder(text, path) {
281
+ var $input = Docsify.dom.getNode('.search input[type="search"]');
282
+
283
+ if (!$input) {
284
+ return
285
+ }
286
+ if (typeof text === 'string') {
287
+ $input.placeholder = text;
288
+ } else {
289
+ var match = Object.keys(text).filter(function (key) { return path.indexOf(key) > -1; })[0];
290
+ $input.placeholder = text[match];
291
+ }
292
+ }
293
+
294
+ function updateNoData(text, path) {
295
+ if (typeof text === 'string') {
296
+ NO_DATA_TEXT = text;
297
+ } else {
298
+ var match = Object.keys(text).filter(function (key) { return path.indexOf(key) > -1; })[0];
299
+ NO_DATA_TEXT = text[match];
300
+ }
301
+ }
302
+
303
+ function updateOptions(opts) {
304
+ options = opts;
305
+ }
306
+
307
+ function init(opts, vm) {
308
+ var keywords = vm.router.parse().query.s;
309
+
310
+ updateOptions(opts);
311
+ style();
312
+ tpl(keywords);
313
+ bindEvents();
314
+ keywords && setTimeout(function (_) { return doSearch(keywords); }, 500);
315
+ }
316
+
317
+ function update(opts, vm) {
318
+ updateOptions(opts);
319
+ updatePlaceholder(opts.placeholder, vm.route.path);
320
+ updateNoData(opts.noData, vm.route.path);
321
+ }
322
+
323
+ var CONFIG = {
324
+ placeholder: 'Type to search',
325
+ noData: 'No Results!',
326
+ paths: 'auto',
327
+ depth: 2,
328
+ maxAge: 86400000, // 1 day
329
+ hideOtherSidebarContent: false,
330
+ namespace: undefined
331
+ };
332
+
333
+ var install = function (hook, vm) {
334
+ var util = Docsify.util;
335
+ var opts = vm.config.search || CONFIG;
336
+
337
+ if (Array.isArray(opts)) {
338
+ CONFIG.paths = opts;
339
+ } else if (typeof opts === 'object') {
340
+ CONFIG.paths = Array.isArray(opts.paths) ? opts.paths : 'auto';
341
+ CONFIG.maxAge = util.isPrimitive(opts.maxAge) ? opts.maxAge : CONFIG.maxAge;
342
+ CONFIG.placeholder = opts.placeholder || CONFIG.placeholder;
343
+ CONFIG.noData = opts.noData || CONFIG.noData;
344
+ CONFIG.depth = opts.depth || CONFIG.depth;
345
+ CONFIG.hideOtherSidebarContent = opts.hideOtherSidebarContent || CONFIG.hideOtherSidebarContent;
346
+ CONFIG.namespace = opts.namespace || CONFIG.namespace;
347
+ }
348
+
349
+ var isAuto = CONFIG.paths === 'auto';
350
+
351
+ hook.mounted(function (_) {
352
+ init(CONFIG, vm);
353
+ !isAuto && init$1(CONFIG, vm);
354
+ });
355
+ hook.doneEach(function (_) {
356
+ update(CONFIG, vm);
357
+ isAuto && init$1(CONFIG, vm);
358
+ });
359
+ };
360
+
361
+ $docsify.plugins = [].concat(install, $docsify.plugins);
362
+
363
+ }());
364
+
@@ -56,18 +56,23 @@ a {
56
56
  text-align: center;
57
57
  }
58
58
 
59
-
60
- aside.sidebar {
59
+ .sidebar {
61
60
  border: none;
62
61
  background-color: var(--theme-color-secondary);
63
62
  color: #fff;
64
63
  width: 20%;
64
+ display: flex;
65
+ flex-direction: column;
65
66
  }
66
67
 
67
68
  body.close .sidebar {
68
69
  transform: translateX(-100%);
69
70
  }
70
71
 
72
+ .sidebar .sidebar-nav {
73
+ order: 3;
74
+ }
75
+
71
76
  .sidebar ul li a {
72
77
  color: rgba(255,255,255,0.8);
73
78
  color: var(--theme-color-light);
@@ -89,7 +94,32 @@ body.close .sidebar {
89
94
  }
90
95
 
91
96
  .sidebar > h1 {
97
+ order: 1;
92
98
  font-size: 2rem;
99
+ margin-top: 1.5rem;
100
+ }
101
+
102
+ /* search plugin related */
103
+
104
+ .sidebar .search {
105
+ order: 2;
106
+ margin: 1.5rem 0 0 0;
107
+ border: none;
108
+ margin-top: 20px;
109
+ margin-bottom: 20px;
110
+ padding: 6px;
111
+ }
112
+
113
+ .sidebar .search .input-wrap {
114
+ border: none;
115
+ position: relative;
116
+ }
117
+
118
+ .sidebar .search .clear-button.show {
119
+ display: block;
120
+ position: absolute;
121
+ right: 4px;
122
+ top: 8px;
93
123
  }
94
124
 
95
125
  body .sidebar-toggle {
@@ -12,6 +12,7 @@ class ActionPolicy::Base
12
12
  include ActionPolicy::Policy::PreCheck
13
13
  include ActionPolicy::Policy::Reasons
14
14
  include ActionPolicy::Policy::Aliases
15
+ include ActionPolicy::Policy::Scoping
15
16
  include ActionPolicy::Policy::Cache
16
17
  include ActionPolicy::Policy::CachedApply
17
18
  include ActionPolicy::Policy::Defaults
@@ -15,7 +15,7 @@ module ActionPolicy
15
15
  module Draper
16
16
  def policy_for(record:, **opts)
17
17
  # From https://github.com/GoodMeasuresLLC/draper-cancancan/blob/master/lib/draper/cancancan.rb
18
- record = record.model while record.is_a?(Draper::Decorator)
18
+ record = record.model while record.is_a?(::Draper::Decorator)
19
19
  super(record: record, **opts)
20
20
  end
21
21
  end
@@ -30,10 +30,14 @@
30
30
  loadSidebar: true,
31
31
  subMaxLevel: 3,
32
32
  ga: 'UA-104346673-3',
33
- auto2top:true
33
+ auto2top: true,
34
+ search: {
35
+ namespace: 'action-policy'
36
+ }
34
37
  }
35
38
  </script>
36
39
  <script src="assets/docsify.min.js"></script>
40
+ <script src="assets/docsify-search.js"></script>
37
41
  <script src="assets/prism-ruby.min.js"></script>
38
42
  </body>
39
43
  </html>
@@ -13,7 +13,10 @@ module ActionPolicy
13
13
 
14
14
  def initialize(target, message = nil)
15
15
  @target = target
16
- @message = message || "Couldn't find policy class for #{target.inspect}"
16
+ @message =
17
+ message ||
18
+ "Couldn't find policy class for #{target.inspect}" \
19
+ "#{target.is_a?(Module) ? "" : " (#{target.class})"}"
17
20
  end
18
21
  end
19
22
 
@@ -124,15 +124,14 @@ module ActionPolicy
124
124
  def scoping_handlers
125
125
  return @scoping_handlers if instance_variable_defined?(:@scoping_handlers)
126
126
 
127
- @scoping_handlers = Hash.new { |h, k| h[k] = {} }
128
-
129
- if superclass.respond_to?(:scoping_handlers)
130
- superclass.scoping_handlers.each do |k, v|
131
- @scoping_handlers[k] = v.dup
127
+ @scoping_handlers =
128
+ Hash.new { |h, k| h[k] = {} }.tap do |handlers|
129
+ if superclass.respond_to?(:scoping_handlers)
130
+ superclass.scoping_handlers.each do |k, v|
131
+ handlers[k] = v.dup
132
+ end
133
+ end
132
134
  end
133
- end
134
-
135
- @scoping_handlers
136
135
  end
137
136
 
138
137
  # Define scope type matcher.
@@ -149,11 +148,12 @@ module ActionPolicy
149
148
  def scope_matchers
150
149
  return @scope_matchers if instance_variable_defined?(:@scope_matchers)
151
150
 
152
- @scope_matchers = []
153
-
154
- @scope_matchers = superclass.scope_matchers.dup if superclass.respond_to?(:scope_matchers)
155
-
156
- @scope_matchers
151
+ @scope_matchers =
152
+ if superclass.respond_to?(:scope_matchers)
153
+ superclass.scope_matchers.dup
154
+ else
155
+ []
156
+ end
157
157
  end
158
158
  end
159
159
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionPolicy
4
- VERSION = "0.3.1"
4
+ VERSION = "0.3.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_policy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-30 00:00:00.000000000 Z
11
+ date: 2019-06-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -165,6 +165,7 @@ files:
165
165
  - docs/README.md
166
166
  - docs/_sidebar.md
167
167
  - docs/aliases.md
168
+ - docs/assets/docsify-search.js
168
169
  - docs/assets/docsify.min.js
169
170
  - docs/assets/fonts/FiraCode-Medium.woff
170
171
  - docs/assets/fonts/FiraCode-Regular.woff