Class: Tailor::Rulers::IndentationSpacesRuler::IndentationManager
- Inherits:
-
Object
- Object
- Tailor::Rulers::IndentationSpacesRuler::IndentationManager
- Includes:
- LexerConstants, Logger::Mixin
- Defined in:
- lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb
Overview
Used for managing the state of indentation for some file/text. An object of this type has no knowledge of the file/text itself, but rather just manages indentation expectations based on the object’s user’s input, somewhat like a state machine.
For the sake of talking about indentation expectations, the docs here make mention of ‘levels’ of indentation. A level here is simply 1 * (number of spaces to indent); so if you’ve set (number of spaces to indent) to 2, saying something should be indented 1 level, is simply saying that it should be indented 2 spaces.
Constant Summary collapse
- ENCLOSERS =
These are event names generated by the Lexer that signify indentation level should/could increase by 1.
Set.new [:on_lbrace, :on_lbracket, :on_lparen]
- OPEN_EVENT_FOR =
Look-up table that allows for
OPEN_EVENT_FOR[:on_rbrace]
. { on_kw: :on_kw, on_rbrace: :on_lbrace, on_rbracket: :on_lbracket, on_rparen: :on_lparen }
Constants included from LexerConstants
LexerConstants::CONTINUATION_KEYWORDS, LexerConstants::KEYWORDS_AND_MODIFIERS, LexerConstants::KEYWORDS_TO_INDENT, LexerConstants::LOOP_KEYWORDS, LexerConstants::MODIFIERS, LexerConstants::MULTILINE_OPERATORS
Instance Attribute Summary collapse
-
#actual_indentation ⇒ Fixnum
readonly
The actual number of characters the current line is indented.
-
#amount_to_change_this ⇒ Object
Allows for updating the indent expectation for the current line.
-
#indent_reasons ⇒ Array<Hash>
readonly
Each element represents a reason why code should be indented.
Instance Method Summary collapse
-
#add_indent_reason(event_type, token, lineno) ⇒ Object
Adds to the list of reasons to indent the next line, then increases the expectation for the next line by @spaces.
-
#decrease_this_line ⇒ Object
Decreases the indentation expectation for the current line by 1 level.
-
#in_an_enclosure? ⇒ Boolean
Determines if the current spot in the file is enclosed in braces, brackets, or parens.
-
#initialize(spaces) ⇒ IndentationManager
constructor
A new instance of IndentationManager.
- #last_indent_reason_type ⇒ Object
-
#last_opening_event(closing_event_type) ⇒ Object
Returns the last matching opening event that corresponds to the
closing_event_type
. -
#last_single_token_event ⇒ Object
A “single-token” event is one that that causes indentation expectations to increase.
-
#line_ends_with_same_as_last(token_event) ⇒ Boolean
Checks to see if the last token in @single_tokens is the same as the one in
token_event
. -
#line_ends_with_single_token_indenter?(lexed_line) ⇒ Boolean
Checks if the current line ends with an operator, comma, or period.
-
#method_missing(meth, *args, &blk) ⇒ Boolean
Overriding to be able to call
#multi_line_brackets?
,#multi_line_braces?
, and#multi_line_parens?
, where each takes a single parameter, which is the lineno. -
#remove_appropriate_reason(closing_event_type) ⇒ Object
Removes the last matching opening reason reason of
event_type
from the list of indent reasons. -
#remove_continuation_keywords ⇒ Object
Removes all continuation keywords from the list of indentation reasons.
-
#set_up_line_transition ⇒ Object
Sets up expectations in @proper based on the number of /- reasons to change this and next lines, given in @amount_to_change_this+.
-
#should_be_at ⇒ Fixnum
The indent level the file should currently be at.
-
#start ⇒ Object
Starts the process of increasing/decreasing line indentation expectations.
-
#started? ⇒ Boolean
Tells if the indentation checking process is on.
-
#stop ⇒ Object
Stops the process of increasing/decreasing line indentation expectations.
-
#transition_lines ⇒ Object
Should be called just before moving to the next line.
-
#update_actual_indentation(lexed_line_output) ⇒ Object
Updates @actual_indentation based on the given lexed_line_output.
-
#update_for_closing_reason(event_type, lexed_line) ⇒ Object
A “closing reason” is a reason for indenting that also has an “opening reason”, such as a
end
, },]
, ). -
#update_for_continuation_reason(token, lexed_line, lineno) ⇒ Object
A “continuation reason” is a reason for indenting & outdenting that’s not an opening or closing reason, such as
elsif
,rescue
,when
(in acase
statement), etc. -
#update_for_opening_reason(event_type, token, lineno) ⇒ Object
An “opening reason” is a reason for indenting that also has a “closing reason”, such as a
def
, {,[
, (..
Methods included from Logger::Mixin
Constructor Details
#initialize(spaces) ⇒ IndentationManager
Returns a new instance of IndentationManager.
49 50 51 52 53 54 55 56 57 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 49 def initialize(spaces) @spaces = spaces @proper = { this_line: 0, next_line: 0 } @actual_indentation = 0 @indent_reasons = [] @amount_to_change_this = 0 start end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(meth, *args, &blk) ⇒ Boolean
Overriding to be able to call #multi_line_brackets?
, #multi_line_braces?
, and #multi_line_parens?
, where each takes a single parameter, which is the lineno.
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 375 def method_missing(meth, *args, &blk) if meth.to_s =~ /^multi_line_(.+)\?$/ token = case $1 when "brackets" then '[' when "braces" then '{' when "parens" then '(' else super(meth, *args, &blk) end lineno = args.first tokens = @indent_reasons.find_all do |t| t[:token] == token end log "#{meth} called, but no #{$1} were found." if tokens.empty? return false if tokens.empty? token_on_this_line = tokens.find { |t| t[:lineno] == lineno } return true if token_on_this_line.nil? false else super(meth, *args, &blk) end end |
Instance Attribute Details
#actual_indentation ⇒ Fixnum (readonly)
Returns The actual number of characters the current line is indented.
40 41 42 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 40 def actual_indentation @actual_indentation end |
#amount_to_change_this ⇒ Object
Allows for updating the indent expectation for the current line.
36 37 38 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 36 def amount_to_change_this @amount_to_change_this end |
#indent_reasons ⇒ Array<Hash> (readonly)
Returns Each element represents a reason why code should be indented. Indent levels are not necessarily 1:1 relationship to these reasons (hence the need for this class).
45 46 47 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 45 def indent_reasons @indent_reasons end |
Instance Method Details
#add_indent_reason(event_type, token, lineno) ⇒ Object
Adds to the list of reasons to indent the next line, then increases the expectation for the next line by @spaces.
199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 199 def add_indent_reason(event_type, token, lineno) @indent_reasons << { event_type: event_type, token: token, lineno: lineno, should_be_at: @proper[:this_line] } @proper[:next_line] = @indent_reasons.last[:should_be_at] + @spaces log "Added indent reason; it's now:" @indent_reasons.each { |r| log r.to_s } end |
#decrease_this_line ⇒ Object
Decreases the indentation expectation for the current line by 1 level.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 66 def decrease_this_line if started? @proper[:this_line] -= @spaces if @proper[:this_line] < 0 @proper[:this_line] = 0 end log "@proper[:this_line] = #{@proper[:this_line]}" log "@proper[:next_line] = #{@proper[:next_line]}" else log "#decrease_this_line called, but checking is stopped." end end |
#in_an_enclosure? ⇒ Boolean
Determines if the current spot in the file is enclosed in braces, brackets, or parens.
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 172 def in_an_enclosure? return false if @indent_reasons.empty? i_reasons = @indent_reasons.dup log "i reasons: #{i_reasons}" until ENCLOSERS.include? i_reasons.last[:event_type] i_reasons.pop break if i_reasons.empty? end return false if i_reasons.empty? i_reasons.last[:event_type] == :on_lbrace || i_reasons.last[:event_type] == :on_lbracket || i_reasons.last[:event_type] == :on_lparen end |
#last_indent_reason_type ⇒ Object
354 355 356 357 358 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 354 def last_indent_reason_type return if @indent_reasons.empty? @indent_reasons.last[:event_type] end |
#last_opening_event(closing_event_type) ⇒ Object
Returns the last matching opening event that corresponds to the closing_event_type
.
346 347 348 349 350 351 352 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 346 def last_opening_event(closing_event_type) return nil if @indent_reasons.empty? @indent_reasons.reverse.find do |r| r[:event_type] == OPEN_EVENT_FOR[closing_event_type] end end |
#last_single_token_event ⇒ Object
A “single-token” event is one that that causes indentation expectations to increase. They don’t have have a paired closing reason like opening reasons. Instead, they’re determined to be done with their indenting when an :on_ignored_nl occurs. Single-token events are operators and commas (commas that aren’t used as separators in {, [, ( events).
332 333 334 335 336 337 338 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 332 def last_single_token_event return nil if @indent_reasons.empty? @indent_reasons.reverse.find do |r| !ENCLOSERS.include?(r[:event_type]) && r[:event_type] != :on_kw end end |
#line_ends_with_same_as_last(token_event) ⇒ Boolean
Checks to see if the last token in @single_tokens is the same as the one in token_event
.
162 163 164 165 166 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 162 def line_ends_with_same_as_last(token_event) return false if @indent_reasons.empty? @indent_reasons.last[:event_type] == token_event[1] end |
#line_ends_with_single_token_indenter?(lexed_line) ⇒ Boolean
Checks if the current line ends with an operator, comma, or period.
148 149 150 151 152 153 154 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 148 def line_ends_with_single_token_indenter?(lexed_line) lexed_line.ends_with_op? || lexed_line.ends_with_comma? || lexed_line.ends_with_period? || lexed_line.ends_with_label? || lexed_line.ends_with_modifier_kw? end |
#remove_appropriate_reason(closing_event_type) ⇒ Object
Removes the last matching opening reason reason of event_type
from the list of indent reasons.
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 304 def remove_appropriate_reason(closing_event_type) if last_opening_event = last_opening_event(closing_event_type) r_index = @indent_reasons.reverse.index(last_opening_event) index = @indent_reasons.size - r_index - 1 tmp_reasons = [] @indent_reasons.each_with_index do |r, i| tmp_reasons << r unless i == index end @indent_reasons.replace(tmp_reasons) elsif last_single_token_event log "Just popped off reason: #{@indent_reasons.pop}" else log "Couldn't find a matching opening reason to pop off...'" return end log "Removed indent reason; it's now:" @indent_reasons.each { |r| log r.to_s } end |
#remove_continuation_keywords ⇒ Object
Removes all continuation keywords from the list of indentation reasons.
362 363 364 365 366 367 368 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 362 def remove_continuation_keywords return if @indent_reasons.empty? while CONTINUATION_KEYWORDS.include?(@indent_reasons.last[:token]) log "Just popped off continuation reason: #{@indent_reasons.pop}" end end |
#set_up_line_transition ⇒ Object
Sets up expectations in @proper based on the number of /- reasons to change this and next lines, given in @amount_to_change_this+.
83 84 85 86 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 83 def set_up_line_transition log "Amount to change this line: #{@amount_to_change_this}" decrease_this_line if @amount_to_change_this < 0 end |
#should_be_at ⇒ Fixnum
Returns The indent level the file should currently be at.
60 61 62 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 60 def should_be_at @proper[:this_line] end |
#start ⇒ Object
Starts the process of increasing/decreasing line indentation expectations.
105 106 107 108 109 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 105 def start log "Starting indentation ruling." log "Next check should be at #{should_be_at}" @do_measurement = true end |
#started? ⇒ Boolean
Tells if the indentation checking process is on.
114 115 116 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 114 def started? @do_measurement end |
#stop ⇒ Object
Stops the process of increasing/decreasing line indentation expectations.
120 121 122 123 124 125 126 127 128 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 120 def stop if started? msg = "Stopping indentation ruling. Should be: #{should_be_at}; " msg << "actual: #{@actual_indentation}" log msg end @do_measurement = false end |
#transition_lines ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 91 def transition_lines if started? log "Resetting change_this to 0." @amount_to_change_this = 0 log "Setting @proper[:this_line] = that of :next_line" @proper[:this_line] = @proper[:next_line] log "Transitioning @proper[:this_line] to #{@proper[:this_line]}" else log "Skipping #transition_lines; checking is stopped." end end |
#update_actual_indentation(lexed_line_output) ⇒ Object
Updates @actual_indentation based on the given lexed_line_output.
133 134 135 136 137 138 139 140 141 142 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 133 def update_actual_indentation(lexed_line_output) if lexed_line_output.end_of_multi_line_string? log "Found end of multi-line string." return end first_non_space_element = lexed_line_output.first_non_space_element @actual_indentation = first_non_space_element.first.last log "Actual indentation: #{@actual_indentation}" end |
#update_for_closing_reason(event_type, lexed_line) ⇒ Object
A “closing reason” is a reason for indenting that also has an “opening reason”, such as a end
, }, ]
, ).
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 276 def update_for_closing_reason(event_type, lexed_line) remove_continuation_keywords remove_appropriate_reason(event_type) @proper[:next_line] = if @indent_reasons.empty? 0 else @indent_reasons.last[:should_be_at] + @spaces end log "Updated :next after closing; it's now #{@proper[:next_line]}" meth = "only_#{event_type.to_s.sub("^on_", '')}?" if lexed_line.send(meth.to_sym) || lexed_line.to_s =~ /^\s*end\n?$/ @proper[:this_line] = @proper[:this_line] - @spaces msg = "End multi-line statement. " msg < "change_this -= 1 -> #{@proper[:this_line]}." log msg end end |
#update_for_continuation_reason(token, lexed_line, lineno) ⇒ Object
A “continuation reason” is a reason for indenting & outdenting that’s not an opening or closing reason, such as elsif
, rescue
, when
(in a case
statement), etc.
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 244 def update_for_continuation_reason(token, lexed_line, lineno) d_tokens = @indent_reasons.dup d_tokens.pop on_line_token = d_tokens.find { |t| t[:lineno] == lineno } log "online token: #{on_line_token}" if on_line_token.nil? && lexed_line.to_s =~ /^\s*#{token}/ @proper[:this_line] -= @spaces unless @proper[:this_line].zero? msg = "Continuation keyword: '#{token}'. " msg << "change_this -= 1 -> #{@proper[:this_line]}" log msg end last_reason_line = @indent_reasons.find { |r| r[:lineno] == lineno } @proper[:next_line] = if last_reason_line.nil? if @indent_reasons.empty? @spaces else @indent_reasons.last[:should_be_at] + @spaces end else @indent_reasons.last[:should_be_at] - @spaces end end |
#update_for_opening_reason(event_type, token, lineno) ⇒ Object
An “opening reason” is a reason for indenting that also has a “closing reason”, such as a def
, {, [
, (.
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb', line 220 def update_for_opening_reason(event_type, token, lineno) if token.modifier_keyword? log "Found modifier in line: '#{token}'" return end log "Token '#{token}' not used as a modifier." if token.do_is_for_a_loop? log "Found keyword loop using optional 'do'" return end add_indent_reason(event_type, token, lineno) end |