incline 0.1.7 → 0.1.8

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
  SHA1:
3
- metadata.gz: cf198e645fba31e26e730a4fcf2deae2b72a8d92
4
- data.tar.gz: 4c5782b14aa7db868e44ec418f0272aa6cbd026a
3
+ metadata.gz: '0254285858902e4313110fddc419672ac8ae267b'
4
+ data.tar.gz: f22408a384aa6aaf8ee1f36195a220d1677fb09c
5
5
  SHA512:
6
- metadata.gz: e4422ca100423246a3eb80de970c1e6958379b14afc7294c07f4e739f66b3b5442414eae78781d5dc577c303baea32663bb5e3e6dc49f50095dd9afce86b3ed7
7
- data.tar.gz: b84f5223ea71524f0f445a6a5cdf0aacb3d85d6e63b39397b30db8ea3ed4272c9994b98e949247a0167f4c0115e4367118b6bf02d52fb18217d795ceebf4fc11
6
+ metadata.gz: e8f26912a02f65f50705909925952a0478bed454cc32a3d5eff854a1186d030e72905370f3791fd40dae334c72fffad0d8cf2177e4077e8924cdc9b4028ae61a
7
+ data.tar.gz: 200de0b8b26cabf2303f94ee7df3d5aad0c3ec7c7a8745871df0825d3c16e6b4039da7115f50b70972310c661ba0b7ba50ee4a69d292b353cd1714301e3f63a9
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- incline (0.1.7)
4
+ incline (0.1.8)
5
5
  ansi (~> 1.5.0)
6
6
  bcrypt
7
7
  bootstrap-sass
@@ -58,7 +58,7 @@ GEM
58
58
  tzinfo (~> 1.1)
59
59
  ansi (1.5.0)
60
60
  arel (6.0.4)
61
- autoprefixer-rails (7.1.2.2)
61
+ autoprefixer-rails (7.1.2.3)
62
62
  execjs
63
63
  bcrypt (3.1.11)
64
64
  bootstrap-sass (3.3.7)
@@ -151,7 +151,7 @@ GEM
151
151
  sprockets (>= 2.8, < 4.0)
152
152
  sprockets-rails (>= 2.0, < 4.0)
153
153
  tilt (>= 1.1, < 3)
154
- shells (0.1.9)
154
+ shells (0.1.10)
155
155
  net-ssh (~> 3.0.2)
156
156
  rubyserial (~> 0.4.0)
157
157
  spawnling (2.1.6)
@@ -165,7 +165,7 @@ GEM
165
165
  sqlite3 (1.3.13)
166
166
  thor (0.19.4)
167
167
  thread_safe (0.3.6)
168
- tilt (2.0.7)
168
+ tilt (2.0.8)
169
169
  tiny_tds (1.3.0)
170
170
  mini_portile2 (~> 2.0)
171
171
  tzinfo (1.2.3)
@@ -8,7 +8,7 @@ module Incline
8
8
  def edit
9
9
  if logged_in?
10
10
  flash[:danger] = 'You cannot reactivate your account.'
11
- redirect_to root_url
11
+ redirect_to main_app.root_url
12
12
  else
13
13
  user = User.find_by(email: params[:email].downcase)
14
14
  if user && !user.activated? && user.authenticated?(:activation, params[:id])
@@ -18,7 +18,7 @@ module Incline
18
18
  redirect_to user
19
19
  else
20
20
  flash[:danger] = 'Invalid activation link'
21
- redirect_to root_url
21
+ redirect_to main_app.root_url
22
22
  end
23
23
  end
24
24
  end
@@ -17,7 +17,7 @@ module Incline
17
17
  @msg.remote_ip = request.remote_ip
18
18
  @msg.send_message
19
19
  flash[:success] = 'Your message has been sent.'
20
- redirect_to root_url
20
+ redirect_to main_app.root_url
21
21
  else
22
22
  render 'new'
23
23
  end
@@ -40,7 +40,7 @@ module Incline
40
40
  end
41
41
 
42
42
  flash[:info] = 'An email with password reset information has been sent to you.'
43
- redirect_to root_url
43
+ redirect_to main_app.root_url
44
44
  end
45
45
 
46
46
  ##
@@ -98,7 +98,7 @@ module Incline
98
98
 
99
99
  def valid_user
100
100
  unless @user && @user.enabled? && @user.activated? && @user.authenticated?(:reset, params[:id])
101
- redirect_to root_url
101
+ redirect_to main_app.root_url
102
102
  end
103
103
  end
104
104
 
@@ -29,7 +29,7 @@ module Incline
29
29
  redirect_back_or @user
30
30
  else
31
31
  flash[:safe_warning] = 'Your account has not yet been activated.<br/>Check your email for the activation link.'
32
- redirect_to root_url
32
+ redirect_to main_app.root_url
33
33
  end
34
34
  else
35
35
  # deny login.
@@ -42,7 +42,7 @@ module Incline
42
42
  # DELETE /incline/logout
43
43
  def destroy
44
44
  log_out if logged_in?
45
- redirect_to root_url
45
+ redirect_to main_app.root_url
46
46
  end
47
47
 
48
48
  end
@@ -59,7 +59,7 @@ module Incline
59
59
  if inline_request?
60
60
  render 'show', formats: [ :json ]
61
61
  else
62
- redirect_to root_url
62
+ redirect_to main_app.root_url
63
63
  end
64
64
  return
65
65
  end
data/exe/incline ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # If installed as a gem, this won't do anything, however if we are
4
+ # working from the source, this will ensure our lib path is searched
5
+ # for require and include calls.
6
+ git_path = File.expand_path('../../.git', __FILE__)
7
+ if File.exist?(git_path)
8
+ $:.unshift File.expand_path('../../lib', __FILE__)
9
+ end
10
+
11
+ require 'incline/cli'
12
+ Incline::CLI.new.execute(*ARGV)
@@ -0,0 +1,8 @@
1
+ module Incline
2
+ class CLI
3
+
4
+ class CliError < ::RuntimeError; end
5
+ class UsageError < CliError; end
6
+
7
+ end
8
+ end
@@ -0,0 +1,743 @@
1
+ module Incline
2
+ module CliHelpers
3
+
4
+ ##
5
+ # Adds YAML text helper methods.
6
+ #
7
+ # Does not parse YAML files, but does allow for updating raw text files to be YAML compliant.
8
+ module Yaml
9
+
10
+ class YamlError < ::Incline::CLI::CliError; end
11
+
12
+ ##
13
+ # Helper class to process the YAML file contents easily.
14
+ class YamlContents
15
+
16
+ ##
17
+ # Creates a new YAML contents.
18
+ def initialize(content)
19
+ @content = content.to_s.gsub("\r\n", "\n").strip + "\n"
20
+ end
21
+
22
+ ##
23
+ # Returns the YAML contents.
24
+ def to_s
25
+ @content
26
+ end
27
+
28
+ ##
29
+ # Adds a key to the YAML contents if it is missing.
30
+ # Does nothing to the key if it exists.
31
+ #
32
+ # add_key [ "default", "name" ], "george"
33
+ #
34
+ # The 'key' should be an array defining the path.
35
+ #
36
+ # Value can be nil, a string, a symbol, a number, or a boolean.
37
+ #
38
+ # The 'make_safe_value' option can be used to provide an explicit text value.
39
+ # This can be useful if you want to add a specific value, like an ERB command.
40
+ #
41
+ # add_key [ "default", "name" ], "<%= ENV[\"DEFAULT_USER\"] %>", false
42
+ #
43
+ # You can also use a hash for the value to specify advanced options.
44
+ # Currently only three advanced options are recognized.
45
+ #
46
+ # The first option, :value, simply sets the value. If this is the only
47
+ # hash key provided, then the value supplied is treated as if it was the original
48
+ # value. In other words, only setting :value is the same as not using a hash and
49
+ # just passing in the value, so the value must be nil, a string, a symbol, a number,
50
+ # or a boolean.
51
+ #
52
+ # The second option, :safe, works the opposite of the 'make_safe_value' parameter.
53
+ # If :safe is a non-false value, then it is like 'make_safe_value' is set to false.
54
+ # If :safe is a false value, then it is like 'make_safe_value' is set to true.
55
+ # The :safe value can be set to true and the :value option can set the value, or
56
+ # the :safe value can be set to the value directly since all strings are non-false.
57
+ #
58
+ # The third option, :before_section, tells add_key to insert the section before the
59
+ # named section (if the new section doesn't exist). This can be useful if the named
60
+ # section is going to be referencing the key you are adding. Otherwise, when a
61
+ # section needs to be added, it gets added to the end of the file.
62
+ #
63
+ # Returns the contents object.
64
+ def add_key(key, value, make_safe_value = true)
65
+
66
+ # ensure the parent structure exists!
67
+ if key.count > 1
68
+ add_key(key[0...-1], nil)
69
+ else
70
+ # If the base key already exists, no need to look further.
71
+ return self if @content =~ /^#{key.first}:/
72
+
73
+ unless @content[0] == '#'
74
+ @content = "# File modified by Incline v#{Incline::VERSION}.\n" + @content
75
+ end
76
+ end
77
+
78
+ val_name = key.last
79
+
80
+ # construct a regular expression to find the parent group and value.
81
+ rex_str = '^('
82
+ rex_prefix = /\A./
83
+ key.each_with_index do |attr,level|
84
+ lev = (level < 1 ? '' : ('\\s\\s' * (level)))
85
+ if lev != ''
86
+ rex_str += '(?:' + lev + '[^\\n]*\\n)*'
87
+ end
88
+ if level == key.count - 1
89
+ if level == 0
90
+ # At level 0 we cheat and use a very simple regular expression to confirm the section exists.
91
+ rex_str = "^#{attr}:"
92
+ # If it doesn't exists, the prefix regex will usually want to put the new section at the end of the
93
+ # file. However if the :before_section option is set, and the other section exists, then we
94
+ # want to ensure that we are putting the new section before it.
95
+ #
96
+ # Down below we take care to reverse the replacement string when key.count == 1.
97
+ rex_prefix =
98
+ if value.is_a?(::Hash) && value[:before_section] && @content =~ /^#{value[:before_section]}:/
99
+ /(^#{value[:before_section]}:)/
100
+ else
101
+ /(\z)/ # match the end of the contents.
102
+ end
103
+ else
104
+ rex_str += ')'
105
+ rex_prefix = Regexp.new(rex_str)
106
+ rex_str += '(' + lev + attr + ':.*\\n)'
107
+ end
108
+ else
109
+ rex_str += lev + attr + ':.*\\n'
110
+ end
111
+ end
112
+
113
+ rex = Regexp.new(rex_str)
114
+
115
+ if @content =~ rex
116
+ # all good.
117
+ elsif @content =~ rex_prefix
118
+ if make_safe_value
119
+ value = safe_value(value)
120
+ value = add_value_offset(key, value)
121
+ elsif value.is_a?(::Hash)
122
+ value = value[:value]
123
+ end
124
+ value = '' if value =~ /\A\s*\z/
125
+ # Should be true thanks to first step in this method.
126
+ # Capture 1 would be the parent group.
127
+ # When key.count == 1 then we want to put our new value before capture 1.
128
+ # Otherwise we put our new value after capture 1.
129
+ rep = if key.count == 1
130
+ "\n#{val_name}:#{value}\n\\1"
131
+ else
132
+ "\\1#{' ' * (key.count - 1)}#{val_name}:#{value}\n"
133
+ end
134
+
135
+ @content.gsub! rex_prefix, rep
136
+ else
137
+ raise ::Incline::CliHelpers::Yaml::YamlError, "Failed to create parent group for '#{key.join('/')}'."
138
+ end
139
+
140
+ self
141
+ end
142
+
143
+
144
+ ##
145
+ # Adds a key to the YAML contents if it is missing.
146
+ # Does nothing to the key if it exists.
147
+ #
148
+ # add_key_with_comment [ "default", "name" ], "george", "this is the name of the default user"
149
+ #
150
+ # The 'key' should be an array defining the path.
151
+ # If the 'comment' is blank (nil or ''), then it will not modify the comment.
152
+ # Use a whitespace string (' ') to indicate that you want a blank comment added.
153
+ #
154
+ # Value can be nil, a string, a symbol, a number, or a boolean.
155
+ # Value can also be a hash according to #add_key.
156
+ #
157
+ # Returns the contents object.
158
+ def add_key_with_comment(key, value, comment)
159
+ if comment.to_s == ''
160
+ add_key key, value
161
+ else
162
+ add_key key, value_with_comment(key, value, comment), false
163
+ end
164
+ end
165
+
166
+ ##
167
+ # Sets a key in the YAML contents.
168
+ # Adds the key if it is missing, replaces it if it already exists.
169
+ #
170
+ # set_key [ "default", "name" ], "george"
171
+ #
172
+ # The 'key' should be an array defining the path.
173
+ #
174
+ # Value can be nil, a string, a symbol, a number, or a boolean.
175
+ # Value can also be a hash according to #add_key.
176
+ #
177
+ # The 'make_safe_value' option can be used to provide an explicit text value.
178
+ # This can be useful if you want to add a specific value, like an ERB command.
179
+ #
180
+ # set_key [ "default", "name" ], "<%= ENV[\"DEFAULT_USER\"] %>", false
181
+ #
182
+ # Returns the contents object.
183
+ def set_key(key, value, make_safe_value = true)
184
+
185
+ # construct a regular expression to find the value and not confuse it with any other value in the file.
186
+ rex_str = '^('
187
+ key.each_with_index do |attr,level|
188
+ lev = (level < 1 ? '' : ('\\s\\s' * (level)))
189
+ if lev != ''
190
+ rex_str += '(?:' + lev + '.*\\n)*'
191
+ end
192
+ if level == key.count - 1
193
+ rex_str += lev + attr + ':)\\s*([^#\\n]*)?(#[^\\n]*)?\\n'
194
+ else
195
+ rex_str += lev + attr + ':.*\\n'
196
+ end
197
+ end
198
+
199
+ rex = Regexp.new(rex_str)
200
+
201
+ if @content =~ rex
202
+ if make_safe_value
203
+ value = safe_value(value)
204
+ value = add_value_offset(key, value)
205
+ elsif value.is_a?(::Hash)
206
+ value = value[:value]
207
+ end
208
+ value = '' if value =~ /\A\s*\z/
209
+ # Capture 1 is everything before the value.
210
+ # Capture 2 is going to be just the value.
211
+ # Capture 3 is the comment (if any). This allows us to propagate comments if we change a value.
212
+ if $2 != value
213
+ rep = "\\1#{value}\\3\n"
214
+ @content.gsub! rex, rep
215
+ end
216
+
217
+ self
218
+ else
219
+ add_key(key, value, make_safe_value)
220
+ end
221
+ end
222
+
223
+ ##
224
+ # Sets a key in the YAML contents.
225
+ # Adds the key if it is missing, replaces it if it already exists.
226
+ #
227
+ # set_key_with_comment [ "default", "name" ], "george", "this is the name of the default user"
228
+ #
229
+ # The 'key' should be an array defining the path.
230
+ # If the 'comment' is blank (nil or ''), then it will not modify the comment.
231
+ # Use a whitespace string (' ') to indicate that you want a blank comment added.
232
+ #
233
+ # Value can be nil, a string, a symbol, a number, or a boolean.
234
+ # Value can also be a hash according to #add_key.
235
+ #
236
+ # Returns the contents object.
237
+ def set_key_with_comment(key, value, comment)
238
+ if comment.to_s == ''
239
+ set_key key, value
240
+ else
241
+ set_key key, value_with_comment(key, value, comment), false
242
+ end
243
+ end
244
+
245
+ ##
246
+ # Removes the specified key from the contents.
247
+ #
248
+ # Returns an array containing the contents of the key.
249
+ # The first element will be for the key itself. If the
250
+ # key had child keys, then they will also be included in
251
+ # the array.
252
+ #
253
+ # The returned array will contain hashes for each removed
254
+ # key.
255
+ #
256
+ # data = remove_key %w(pet dog)
257
+ #
258
+ # [
259
+ # {
260
+ # :key => [ "pet", "dog" ],
261
+ # :value => "",
262
+ # :safe => true,
263
+ # :comment => "This list has the family dogs."
264
+ # },
265
+ # {
266
+ # :key => [ "pet", "dog", "sadie" ],
267
+ # :value => "",
268
+ # :safe => true,
269
+ # :comment => ""
270
+ # },
271
+ # {
272
+ # :key => [ "pet", "dog", "sadie", "breed" ],
273
+ # :value => "boxer",
274
+ # :safe => true,
275
+ # :comment => ""
276
+ # },
277
+ # {
278
+ # :key => [ "pet", "dog", "sadie", "dob" ],
279
+ # :value => "\"2016-06-01\"",
280
+ # :safe => true,
281
+ # :comment => "Estimated date of birth since she was a rescue."
282
+ # }
283
+ # ]
284
+ #
285
+ # The returned hashes can be fired right back into #add_key.
286
+ #
287
+ # data.each do |item|
288
+ # add_key_with_comment item[:key], item, item[:comment]
289
+ # end
290
+ #
291
+ # This method can be used to move a section within the file.
292
+ #
293
+ # # remove the 'familes' section from the file.
294
+ # section = remove_key [ "families" ]
295
+ # item = section.delete(section.first)
296
+ #
297
+ # # add the 'familes' section back in before the 'pets' section.
298
+ # add_key_with_comment item[:key], { before_section: "pets" }.merge(item), item[:comment]
299
+ #
300
+ # # add the data back into the 'familes' section.
301
+ # section.each do |item|
302
+ # add_key_with_comment item[:key], item, item[:comment]
303
+ # end
304
+ #
305
+ def remove_key(key)
306
+ rex_str = '(^'
307
+ key.each_with_index do |attr,level|
308
+ lev = (level < 1 ? '' : ('\\s\\s' * level))
309
+ if lev != ''
310
+ rex_str += '(?:' + lev + '.*\\n)*'
311
+ end
312
+ if level == key.count - 1
313
+ if level == 0
314
+ rex_str = '(^)(' + attr + ':[^\\n]*\\n(?:\\s\\s[^\\n]*\\n)*)'
315
+ else
316
+ rex_str += ')(' + lev + attr + ':[^\\n]*\\n(?:' + lev + '\\s\\s[^\\n]*\\n)*)'
317
+ end
318
+ else
319
+ rex_str += lev + attr + ':[^\\n]*\\n'
320
+ end
321
+ end
322
+
323
+ # match result 1 is the parent key structure leading up to the key to be extracted.
324
+ # match result 2 is the key with all child elements to be extracted.
325
+
326
+ rex = Regexp.new(rex_str)
327
+
328
+ if @content =~ rex
329
+
330
+ # cache the key contents
331
+ key_content = $2
332
+
333
+ # remove the key from the main contents.
334
+ @content.gsub!(rex, "\\1")
335
+
336
+ # and separate into lines.
337
+ lines = extract_to_array(key_content)
338
+
339
+ ret = []
340
+
341
+ base_key = key.length == 1 ? [] : key[0...-1]
342
+
343
+ last_line = nil
344
+
345
+ lines.each do |line|
346
+ level = line[:level]
347
+ if level > 0 && line[:key]
348
+ # go from base 1 to base 0
349
+ level -= 1
350
+
351
+ # make sure the base key is the right length for the current key.
352
+ while level > base_key.length
353
+ base_key.push '?' # hopefully this never occurs.
354
+ end
355
+ while level < base_key.length
356
+ base_key.pop
357
+ end
358
+
359
+ # add our key to the base key.
360
+ # if the next key is below it, this ensures the parent structure is correct.
361
+ # if the next key is higher or at the same level the above loops should make it correct.
362
+ base_key << line[:key]
363
+
364
+ last_line = {
365
+ key: base_key,
366
+ value: line[:value].to_s,
367
+ comment: line[:comment],
368
+ safe: true
369
+ }
370
+
371
+ ret << last_line
372
+ elsif level > 0 && line[:comment]
373
+ if last_line && last_line[:key].length == level
374
+ if last_line[:comment]
375
+ last_line[:comment] += "\n" + line[:comment]
376
+ else
377
+ last_line[:comment] = "\n" + line[:comment]
378
+ end
379
+ end
380
+ end
381
+ end
382
+
383
+ ret
384
+ else
385
+ []
386
+ end
387
+ end
388
+
389
+ ##
390
+ # Realigns the file.
391
+ #
392
+ # All values and comments will line up at each level when complete.
393
+ def realign!
394
+ lines = extract_to_array(@content)
395
+
396
+ # reset the offsets.
397
+ value_offsets.clear
398
+ comment_offsets.clear
399
+
400
+ # get value offsets.
401
+ lines.each do |line|
402
+ level = line[:level]
403
+ if level > 0 && line[:key]
404
+ key_len = line[:key].length + 2 # include the colon and a space
405
+ if key_len > level_value_offset(level)
406
+ set_level_value_offset level, key_len
407
+ end
408
+ end
409
+ end
410
+
411
+ # get comment offsets.
412
+ lines.each do |line|
413
+ level = line[:level]
414
+ if level > 0 && line[:value]
415
+ voff = level_value_offset(level)
416
+ val_len = line[:value] ? line[:value].length : 0
417
+ coff = voff + val_len + 1 # add a space after the value.
418
+ if coff > level_comment_offset(level)
419
+ set_level_comment_offset level, coff
420
+ end
421
+ end
422
+ end
423
+
424
+ # convert the lines back into strings with proper spacing.
425
+ lines = lines.map do |line|
426
+ level = line[:level]
427
+ if level > 0
428
+ if line[:key]
429
+ # a key: value line.
430
+ key = line[:key] + ':'
431
+ key = key.ljust(level_value_offset(level), ' ') unless line[:value].to_s == '' && line[:comment].to_s == ''
432
+ val = line[:value].to_s
433
+ val = val.ljust(level_comment_offset(level) - level_value_offset(level), ' ') unless line[:comment].to_s == ''
434
+ comment = line[:comment] ? "# #{line[:comment]}" : ''
435
+ (' ' * (level - 1)) + key + val + comment
436
+ else
437
+ # just a comment line.
438
+ (' ' * (level - 1)) +
439
+ (' ' * level_comment_offset(level)) +
440
+ "# #{line[:comment]}"
441
+ end
442
+ else
443
+ line[:value] # return the original value
444
+ end
445
+ end
446
+
447
+ @content = lines.join("\n") + "\n"
448
+ end
449
+
450
+ ##
451
+ # Gets the value offset for the specified level.
452
+ #
453
+ # The offset is based on the beginning of the level in question.
454
+ # There will always be at least one whitespace before the value.
455
+ # For instance an offset of 10 for level 2 would be like this:
456
+ #
457
+ # one:
458
+ # two: value
459
+ # some_long_name: value
460
+ # # 0123456789^
461
+ #
462
+ def level_value_offset(level)
463
+ value_offsets[level] || 0
464
+ end
465
+
466
+ ##
467
+ # Sets the value offset for the specified level.
468
+ #
469
+ # The offset is based on the beginning of the level in question.
470
+ # There will always be at least one whitespace before the value.
471
+ # For instance an offset of 10 for level 2 would be like this:
472
+ #
473
+ # one:
474
+ # two: value
475
+ # some_long_name: value
476
+ # # 0123456789^
477
+ #
478
+ def set_level_value_offset(level, offset)
479
+ value_offsets[level] = offset
480
+ end
481
+
482
+ ##
483
+ # Gets the comment offset for the specified level.
484
+ #
485
+ # The offset is based on the beginning of the level in question.
486
+ # There will always be at least one whitespace before the value
487
+ # and at least one whitespace between the value and a comment.
488
+ # For instance an offset of 15 for level 2 would be like this:
489
+ #
490
+ # one:
491
+ # two: value # comment
492
+ # some_long_name: value # comment
493
+ # # 012345678901234^
494
+ #
495
+ def level_comment_offset(level)
496
+ comment_offsets[level] || 0
497
+ end
498
+
499
+ ##
500
+ # Sets the comment offset for the specified level.
501
+ #
502
+ # The offset is based on the beginning of the level in question.
503
+ # There will always be at least one whitespace before the value
504
+ # and at least one whitespace between the value and a comment.
505
+ # For instance an offset of 15 for level 2 would be like this:
506
+ #
507
+ # one:
508
+ # two: value # comment
509
+ # some_long_name: value # comment
510
+ # # 012345678901234^
511
+ #
512
+ def set_level_comment_offset(level, offset)
513
+ comment_offsets[level] = offset
514
+ end
515
+
516
+ ##
517
+ # Allows comparing the contents against a regular expression.
518
+ def =~(regexp)
519
+ @content =~ regexp
520
+ end
521
+
522
+ private
523
+
524
+ def extract_to_array(data)
525
+ # match 1 = lead white
526
+ # ([ \t]*)
527
+ # match 2 = key name
528
+ # (\S+):
529
+ # match 3 = value with leading whitespace
530
+ # ((?:[ \t]*(?:"(?:[^"]*(?:(?:\\{1}|\\{3}|\\{5}|\\{7}|\\{9})")?)*"|'(?:[^']*(?:(?:\\{1}|\\{3}|\\{5}|\\{7}|\\{9})')?)*'|[^\s#"']+))*)
531
+ # ignore white between value and comment (if any).
532
+ # [ \t]*
533
+ # match 4 = comment (if any).
534
+ # (?:#([^\n]*))?
535
+ line_regex = /\A([ \t]*)(\S+):((?:[ \t]*(?:"(?:[^"]*(?:(?:\\{1}|\\{3}|\\{5}|\\{7}|\\{9})")?)*"|'(?:[^']*(?:(?:\\{1}|\\{3}|\\{5}|\\{7}|\\{9})')?)*'|[^\s#"']+))*)[ \t]*(?:#([^\n]*))?\z/
536
+ last_level = 0
537
+ data.split("\n").map do |raw_line|
538
+ # assuming the file is valid any lines not matching the regex should be comments or blank.
539
+ match = line_regex.match(raw_line)
540
+ if match # a key: value line
541
+ last_level = (match[1].length / 2).to_i + 1 # one level per 2 spaces.
542
+ {
543
+ level: last_level,
544
+ key: match[2].strip,
545
+ value: match[3] ? match[3].strip : nil,
546
+ comment: match[4] ? match[4].lstrip : nil
547
+ }
548
+ elsif raw_line =~ /\A(\s*)#(.*)\z/ # a comment
549
+ whitespace = $1
550
+ raw_line = $2
551
+ level =
552
+ if whitespace.length >= (last_level * 2)
553
+ last_level
554
+ else
555
+ (whitespace.length / 2).to_i + 1
556
+ end
557
+ raw_line = raw_line[1..-1] if raw_line[0] == ' '
558
+ {
559
+ level: level,
560
+ comment: raw_line
561
+ }
562
+ else
563
+ {
564
+ level: 0,
565
+ value: raw_line
566
+ }
567
+ end
568
+ end
569
+ end
570
+
571
+ def value_with_comment(key, value, comment)
572
+ vh = value.is_a?(::Hash) ? value : { safe: false, value: value, before_section: nil }
573
+ unless vh[:safe]
574
+ vh[:value] = add_comment(key, add_value_offset(key, safe_value(vh[:value])), comment)
575
+ vh[:safe] = true
576
+ end
577
+ vh
578
+ end
579
+
580
+ def add_value_offset(key, safe_value)
581
+ key_len = key.last.to_s.length + 1 # add one for the colon.
582
+ voff = level_value_offset(key.count) - key_len
583
+ voff = 1 if voff < 1
584
+
585
+ (' ' * voff) + safe_value
586
+ end
587
+
588
+ def add_comment(key, safe_value, comment)
589
+ key_len = key.last.to_s.length + 1 # add one for the colon.
590
+ coff = level_comment_offset(key.count) - key_len - safe_value.length
591
+ coff = 1 if coff < 1
592
+ coff_total = ((key.count - 1) * 2) + value.length + coff
593
+
594
+ safe_value + (' ' * coff) + '# ' + comment.to_s.gsub("\r\n", "\n").gsub("\n", "\n#{' ' * coff_total}# ")
595
+ end
596
+
597
+ def value_offsets
598
+ @value_offsets ||= [ ]
599
+ end
600
+
601
+ def comment_offsets
602
+ @comment_offsets ||= [ ]
603
+ end
604
+
605
+ # always returns a string, even for safe values.
606
+ def safe_value(value)
607
+ # Allows the user to specify the value as a hash option without marking it as safe.
608
+ if value.is_a?(::Hash) && value[:value] && !value[:safe]
609
+ value = value[:value]
610
+ end
611
+
612
+ if value.is_a?(::Hash) && value[:safe]
613
+ # If the user specifies a safe value, return it as-is.
614
+ (value[:value] || value[:safe]).to_s
615
+ elsif value.nil?
616
+ # If the value is nil, return an empty string.
617
+ ''
618
+ else
619
+ # Otherwise process the value to make it YAML compliant.
620
+ unless value.is_a?(::String) || value.is_a?(::Symbol) || value.is_a?(::Numeric) || value.is_a?(::TrueClass) || value.is_a?(::FalseClass)
621
+ raise ArgumentError, "'value' must be a value type (string, symbol, number, boolean)"
622
+ end
623
+
624
+ if value.is_a?(::String)
625
+ if value =~ /\A\s*\z/m || # Empty or filled with whitespace
626
+ value =~ /\A\s/m || # Starts with whitespace
627
+ value =~ /\s\z/m || # Ends with whitespace
628
+ value =~ /\A[+-]?\d+(\.\d*)?\z/ || # Contains a probable number
629
+ value =~ /\A0(b[01]*|x[0-9a-f]*)\z/i # Another probable number in binary or hex format.
630
+ value.inspect
631
+ elsif value =~ /\A([0-9]*[a-z]|[a-z])([a-z0-9_ .,=-]*[a-z0-9_])*\z/i
632
+ value
633
+ else
634
+ value.inspect
635
+ end
636
+ else
637
+ value.inspect
638
+ end
639
+ end
640
+
641
+ end
642
+
643
+ end
644
+
645
+ protected
646
+
647
+ ##
648
+ # Repairs a YAML file, creating it if necessary.
649
+ #
650
+ # The optional parameters define what all will be done by this method before yielding to a supplied block.
651
+ # The contents of the YAML file are yielded to the block and the block should return the modified contents.
652
+ #
653
+ # repair_yaml "config/database.yml" do |contents|
654
+ # contents.add_key [ "test", "database" ], "db/test.sqlite3"
655
+ # end
656
+ #
657
+ # If 'env_ref_set' is set to a non-empty value, then it defines the anchor providing default values
658
+ # for the environment sections. The default value is 'default'.
659
+ #
660
+ # If 'ensure_default' is set, then a 'default' section with a 'default' anchor will be created at the
661
+ # beginning of the file unless a 'default' section already exists in the file.
662
+ # The default value is 'true'.
663
+ #
664
+ # If 'ensure_env' is set, then the environment sections will be created if missing. This ensures that
665
+ # a 'development', 'test', and 'production' section all exist. The default value is 'true'.
666
+ #
667
+ # If 'realign' is set, then the entire file will be processed. All values will be aligned at each
668
+ # level and so will all comments. The default is 'true'.
669
+ #
670
+ # The default options on an empty file will generate a 'default' section before yielding and then
671
+ # fill in the environment sections after the block returns.
672
+ #
673
+ # default: &default
674
+ #
675
+ # development:
676
+ # <<: *default
677
+ #
678
+ # test:
679
+ # <<: *default
680
+ #
681
+ # production:
682
+ # <<: *default
683
+ #
684
+ def repair_yaml(filename, env_ref_sect = 'default', ensure_default = true, ensure_env = true, realign = true) # :doc:
685
+ dirty = false
686
+ stat = :updated
687
+
688
+ # ensure the file exists.
689
+ unless File.exist?(filename)
690
+ File.write filename, "# File created by Incline v#{Incline::VERSION}.\n"
691
+ stat = :created
692
+ dirty = true
693
+ end
694
+
695
+ orig_contents = File.read(filename)
696
+
697
+ contents = YamlContents.new(orig_contents)
698
+
699
+ if ensure_default
700
+ contents.set_key %w(default), '&default', false
701
+ end
702
+
703
+ yield contents if block_given?
704
+
705
+ if ensure_env
706
+ %w(development test production).each do |sect|
707
+ contents.add_key [ sect ], nil
708
+ end
709
+ end
710
+
711
+ # Potential bug, and I'm not even sure if it would be or not.
712
+ # But since we use relatively simple regular expressions to perform the set action,
713
+ # the << "key" can only exist once and would be overridden.
714
+ # That means that a section would not be able to include multiple anchors.
715
+ # Like I said before, I'm not sure if that would actually be a bug or not.
716
+ #
717
+ # Luckily, the YAML files aren't meant to be overly complex so this shouldn't show
718
+ # up regularly if at all.
719
+ unless env_ref_sect.to_s.strip == ''
720
+ %w(development test production).each do |sect|
721
+ contents.set_key [ sect, '<<' ], '*' + env_ref_sect
722
+ end
723
+ end
724
+
725
+ contents.realign! if realign
726
+
727
+ unless dirty
728
+ dirty = (orig_contents != contents.to_s)
729
+ end
730
+
731
+ if dirty
732
+ File.write filename, contents.to_s
733
+ say_status stat, filename, :green
734
+ else
735
+ say_status :unchanged, filename, :blue
736
+ end
737
+ end
738
+
739
+
740
+
741
+ end
742
+ end
743
+ end
@@ -0,0 +1,77 @@
1
+
2
+ module Incline
3
+ class CLI
4
+
5
+ ##
6
+ # Defines the 'usage' command for the CLI.
7
+ class Usage
8
+
9
+ ##
10
+ # Creates a new 'usage' command for the CLI.
11
+ def initialize
12
+
13
+ end
14
+
15
+ ##
16
+ # Shows usage information for the application.
17
+ def run
18
+
19
+ commands = Incline::CLI::valid_commands.sort{|a,b| a[0] <=> b[0]}
20
+
21
+ msg = ANSI.ansi(:bold) { "Usage: #{$PROGRAM_NAME} command <arguments>" }
22
+ msg += "\nValid Commands:\n"
23
+
24
+ commands.each do |(name,klass,params)|
25
+ comment = get_run_comment(klass)
26
+ comment = "(No description)" if comment.to_s.strip == ''
27
+ comment = ' ' + comment.gsub("\n", "\n ")
28
+ msg += " #{name}"
29
+ pend = ''
30
+ params.each do |t,p|
31
+ msg += ' '
32
+ if t == :req
33
+ msg += p.to_s
34
+ elsif t == :opt
35
+ msg += '[' + p.to_s
36
+ pend += ']'
37
+ else
38
+ msg += '<...>'
39
+ end
40
+ end
41
+ msg += "\n" + comment + "\n"
42
+ end
43
+
44
+ STDOUT.print msg
45
+ msg
46
+ end
47
+
48
+ private
49
+
50
+ def get_run_comment(klass)
51
+ meth = klass.instance_method(:run)
52
+ return '' unless meth
53
+ file,line_num = meth.source_location
54
+ return '' unless file && line_num
55
+ return '' unless File.exist?(file)
56
+
57
+ source_lines = File.read(file).gsub("\r\n", "\n").split("\n")
58
+
59
+ comments = []
60
+
61
+ # line_num is 1 based so we need to subtract 1 to get the line with the method definition
62
+ # then we subtract 1 again to get the first line before the method definition.
63
+ line_num -= 2
64
+
65
+ while line_num >= 0 && source_lines[line_num] =~ /\A(?:\s*)(?:#(?:\s(.*))?)?\z/
66
+ line = $1.to_s
67
+ comments << line
68
+ line_num -= 1
69
+ end
70
+
71
+ comments.reverse.join("\n")
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,23 @@
1
+
2
+ module Incline
3
+ class CLI
4
+
5
+ ##
6
+ # Defines the 'version' command for the CLI.
7
+ class Version
8
+
9
+ ##
10
+ # Creates a new 'version' command for the CLI.
11
+ def initialize
12
+
13
+ end
14
+
15
+ ##
16
+ # Shows the version of the Incline library.
17
+ def run
18
+ STDOUT.puts "Incline v#{Incline::VERSION}"
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,120 @@
1
+ require 'ansi/code'
2
+ require 'incline/version'
3
+ require 'incline/cli/errors'
4
+
5
+ require 'incline/cli/helpers/yaml'
6
+
7
+ require 'incline/cli/version'
8
+ require 'incline/cli/usage'
9
+
10
+
11
+ module Incline
12
+ class CLI
13
+
14
+
15
+ def initialize
16
+
17
+ end
18
+
19
+ def execute(*args)
20
+ begin
21
+ if args.empty? || %w(usage help /? -? -help --help).include?(args.first)
22
+ process_command(:usage)
23
+ else
24
+ process_command(*args)
25
+ end
26
+ rescue UsageError => err
27
+ STDERR.puts err.message
28
+ process_command(:usage)
29
+ rescue CliError => err
30
+ STDERR.puts ANSI.code(:red) { 'ERROR:' }
31
+ STDERR.puts err.message
32
+ rescue RuntimeError => err
33
+ STDERR.puts ANSI.code(:red) { 'FATAL ERROR:' }
34
+ STDERR.puts err.inspect
35
+ end
36
+ end
37
+
38
+ def process_command(command, *args)
39
+ command = command.to_sym
40
+ cmd_info = self.class.command_list.find{|c| c[:method] == command}
41
+ if cmd_info
42
+ args = args.dup
43
+ args = []
44
+ cmd_info[:new_params].each do |(type,name)|
45
+ if type == :rest
46
+ args += args
47
+ break
48
+ elsif type == :req
49
+ if args.empty?
50
+ raise UsageError, "Missing required parameter '#{name}' for command '#{command}'."
51
+ end
52
+ args << args.delete_at(0)
53
+ elsif type == :opt
54
+ if args.empty?
55
+ break
56
+ else
57
+ args << args.delete_at(0)
58
+ end
59
+ else
60
+ raise UsageError, "Unknown parameter type '#{type}' for command '#{command}'."
61
+ end
62
+ end
63
+ cmd_object = cmd_info[:klass].new(*args)
64
+ cmd_object.send(:run)
65
+ else
66
+ raise UsageError, "Unknown command '#{command}'."
67
+ end
68
+ end
69
+
70
+ def self.valid_commands
71
+ command_list.map do |cmd_info|
72
+ [ cmd_info[:method], cmd_info[:klass], cmd_info[:new_params] ]
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def self.command_list
79
+ @command_list ||=
80
+ begin
81
+ constants.map do |c|
82
+ klass = const_get c
83
+ # class must have a :new class method and a :run instance method.
84
+ if klass.instance_methods.include?(:run) && klass.methods.include?(:new)
85
+ m = klass.method(:new)
86
+ new_params = m.parameters.select{ |p| p[1] && (p[0] == :req || p[0] == :opt || p[0] == :rest) }.freeze
87
+ m = klass.instance_method(:run)
88
+ run_params = m.parameters.select{ |p| p[1] && (p[0] == :req || p[0] == :opt || p[0] == :rest) }.freeze
89
+ if run_params.count == 0
90
+ {
91
+ name: c.to_s,
92
+ method: c.to_s.gsub(/(.)([A-Z])/,"\\1_\\2").downcase.to_sym,
93
+ new_params: new_params,
94
+ klass: klass,
95
+ valid: true
96
+ }
97
+ else
98
+ {
99
+ name: c.to_s,
100
+ valid: false,
101
+ failure_reason: 'Method :run expects parameters.'
102
+ }
103
+ end
104
+ else
105
+ {
106
+ name: c,
107
+ valid: false,
108
+ failure_reason: 'Missing :new or :run.'
109
+ }
110
+ end
111
+ end.select do |c|
112
+ c[:valid]
113
+ end
114
+ end
115
+ end
116
+
117
+
118
+
119
+ end
120
+ end
@@ -318,7 +318,7 @@ module Incline::Extensions
318
318
  rescue ::Incline::NotAuthorized => err
319
319
 
320
320
  flash[:danger] = err.message
321
- redirect_to root_url and return false
321
+ redirect_to main_app.root_url and return false
322
322
  end
323
323
  true
324
324
 
@@ -216,11 +216,17 @@ module Incline::Extensions
216
216
  end
217
217
 
218
218
  ##
219
- # Make sure main_app is available and working correctly.
219
+ # Make sure main_app is available and working correctly in tests.
220
220
  def main_app
221
221
  Rails.application.class.routes.url_helpers
222
222
  end
223
-
223
+
224
+ ##
225
+ # Make sure incline is available and working correctly in tests.
226
+ def incline
227
+ Incline::Engine.routes.url_helpers
228
+ end
229
+
224
230
  ##
225
231
  # Determines if a user is logged into the test session
226
232
  def is_logged_in?
@@ -1,3 +1,3 @@
1
1
  module Incline
2
- VERSION = "0.1.7"
2
+ VERSION = "0.1.8"
3
3
  end
@@ -0,0 +1,88 @@
1
+ require 'test_helper'
2
+ require 'incline/cli'
3
+
4
+ class YamlContentsTest < ActiveSupport::TestCase
5
+
6
+ ALIGNED_YAML = <<-YAML
7
+ default: &default
8
+ alpha: # comment for alpha
9
+ bravo: # comment for bravo
10
+ one: &one
11
+ charlie: # comment for charlie
12
+ item_1: :simple # Level 3 remains aligned in all sections.
13
+ two: &two
14
+ delta:
15
+ item_1: "This is a \\"string\\" with a '#' character in it." # A nice long string on level 3.
16
+ item_2: true # Just true.
17
+ # This comment is aligned with the comment above.
18
+ three: &three
19
+ echo:
20
+ item_1: <%= Rails.application.secrets["db"]["password"] %> # Ironically, the same length as the string above.
21
+ YAML
22
+
23
+ TOP_OF_FILE = "# Top of file.\n"
24
+
25
+ SIMPLE_ADD_KEY_RESULT = <<-YAML.strip
26
+ # Top of file.
27
+
28
+ default:
29
+ one:
30
+ alpha: true
31
+ YAML
32
+
33
+ SIMPLE_REPLACE_RESULT = <<-YAML.strip
34
+ # Top of file.
35
+
36
+ default:
37
+ one:
38
+ alpha: false
39
+ YAML
40
+
41
+ MULTIPLE_ADD_RESULT = <<-YAML.strip
42
+ # Top of file.
43
+
44
+ one:
45
+ alpha: 1
46
+ delta: 4
47
+
48
+ two:
49
+ bravo: 2
50
+ echo: 5
51
+
52
+ three:
53
+ charlie: 3
54
+ foxtrot: 6
55
+ YAML
56
+
57
+ test 'does not modify unnecessarily on realign' do
58
+ contents = Incline::CliHelpers::Yaml::YamlContents.new(ALIGNED_YAML)
59
+ contents.realign!
60
+ assert_equal ALIGNED_YAML, contents.to_s
61
+ end
62
+
63
+ test 'should insert as appropriate' do
64
+ contents = Incline::CliHelpers::Yaml::YamlContents.new(TOP_OF_FILE)
65
+ contents.add_key %w(default one alpha), true
66
+ assert_equal SIMPLE_ADD_KEY_RESULT, contents.to_s.strip
67
+ end
68
+
69
+ test 'should replace as appropriate' do
70
+ contents = Incline::CliHelpers::Yaml::YamlContents.new(SIMPLE_ADD_KEY_RESULT)
71
+ contents.set_key %w(default one alpha), false
72
+ assert_equal SIMPLE_REPLACE_RESULT, contents.to_s.strip
73
+ end
74
+
75
+ test 'multiple add works as expected' do
76
+ contents = Incline::CliHelpers::Yaml::YamlContents.new(TOP_OF_FILE)
77
+
78
+ contents.add_key %w(one alpha), 1
79
+ contents.add_key %w(two bravo), 2
80
+ contents.add_key %w(three charlie), 3
81
+ contents.add_key %w(one delta), 4
82
+ contents.add_key %w(two echo), 5
83
+ contents.add_key %w(three foxtrot), 6
84
+
85
+ assert_equal MULTIPLE_ADD_RESULT, contents.to_s.strip
86
+ end
87
+
88
+ end
@@ -1,13 +1,13 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class WelcomeControllerTest < ActionDispatch::IntegrationTest
4
-
4
+
5
+ # 2017-08-03: root path should be changeable by actual app. remove jumbotron check and instead do some link checks that should always be present.
5
6
  test 'should get root_path' do
6
7
  get root_path
7
8
  assert_response :success
8
9
  assert_select 'title', full_title
9
- assert_select 'div.jumbotron'
10
- assert_select 'a[href=?]', root_path, count: 2
10
+ assert_select 'a[href=?]', main_app.root_path, count: 2
11
11
  assert_select 'a[href=?]', incline.login_path, count: 1
12
12
  assert_select 'a[href=?]', incline.contact_path, count: 1
13
13
  end
@@ -0,0 +1,10 @@
1
+
2
+ class DummyController < ApplicationController
3
+
4
+ allow_anon true
5
+
6
+ def hello
7
+
8
+ end
9
+
10
+ end
@@ -0,0 +1 @@
1
+ <h1>Congrats, this is the DUMMY root.</h1>
@@ -2,5 +2,7 @@ Rails.application.routes.draw do
2
2
 
3
3
  mount Incline::Engine => "/incline"
4
4
 
5
- root 'incline/welcome#home'
5
+ # need to ensure that custom root paths work.
6
+ root 'dummy#hello'
7
+ # root 'incline/welcome#home'
6
8
  end
@@ -131,12 +131,12 @@ module Incline
131
131
  assert_not is_logged_in?
132
132
 
133
133
  # invalid activation token
134
- get incline.edit_account_activation_url('invalid-token', email: user.email)
134
+ get incline.edit_account_activation_path('invalid-token', email: user.email)
135
135
  assert_not is_logged_in?
136
136
  assert_not user.reload.activated?
137
137
 
138
138
  # valid activation token
139
- get incline.edit_account_activation_url(token, email: user.email)
139
+ get incline.edit_account_activation_path(token, email: user.email)
140
140
  assert user.reload.activated?
141
141
  follow_redirect!
142
142
  assert_template 'incline/users/show'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: incline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Beau Barker
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-07-17 00:00:00.000000000 Z
11
+ date: 2017-08-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -378,6 +378,7 @@ files:
378
378
  - db/migrate/20170622195742_add_non_standard_to_action_security.rb
379
379
  - db/migrate/20170622230422_add_visible_to_action_security.rb
380
380
  - db/seeds.rb
381
+ - exe/incline
381
382
  - exe/new_incline_app
382
383
  - lib/generators/incline/install_generator.rb
383
384
  - lib/generators/incline/templates/_app_menu_anon.html.erb
@@ -393,6 +394,11 @@ files:
393
394
  - lib/generators/incline/templates/incline_version.rb
394
395
  - lib/incline.rb
395
396
  - lib/incline/auth_engine_base.rb
397
+ - lib/incline/cli.rb
398
+ - lib/incline/cli/errors.rb
399
+ - lib/incline/cli/helpers/yaml.rb
400
+ - lib/incline/cli/usage.rb
401
+ - lib/incline/cli/version.rb
396
402
  - lib/incline/data_tables_request.rb
397
403
  - lib/incline/date_time_formats.rb
398
404
  - lib/incline/engine.rb
@@ -446,6 +452,7 @@ files:
446
452
  - lib/templates/jbuilder/scaffold/index.json.jbuilder
447
453
  - lib/templates/jbuilder/scaffold/show.json.jbuilder
448
454
  - lib/templates/rails/scaffold_controller/controller.rb
455
+ - test/cli/yaml_contents_test.rb
449
456
  - test/controllers/incline/access_groups_controller_test.rb
450
457
  - test/controllers/incline/access_test_controller_test.rb
451
458
  - test/controllers/incline/contact_controller_test.rb
@@ -458,10 +465,12 @@ files:
458
465
  - test/dummy/app/assets/stylesheets/application.css
459
466
  - test/dummy/app/controllers/application_controller.rb
460
467
  - test/dummy/app/controllers/concerns/.keep
468
+ - test/dummy/app/controllers/dummy_controller.rb
461
469
  - test/dummy/app/helpers/application_helper.rb
462
470
  - test/dummy/app/mailers/.keep
463
471
  - test/dummy/app/models/.keep
464
472
  - test/dummy/app/models/concerns/.keep
473
+ - test/dummy/app/views/dummy/hello.html.erb
465
474
  - test/dummy/app/views/layouts/application.html.erb
466
475
  - test/dummy/app/views/layouts/incline/_app_menu_anon.html.erb
467
476
  - test/dummy/app/views/layouts/incline/_app_menu_authenticated.html.erb