Class: Oppen::Wadler
- Inherits:
-
Object
- Object
- Oppen::Wadler
- Defined in:
- lib/wadler/print.rb
Overview
Wadler.
Defined Under Namespace
Classes: Wrap
Instance Attribute Summary collapse
-
#config ⇒ Config
readonly
The printer's configuration, altering its behavior.
-
#current_indent ⇒ Integer
readonly
The current indentation amount.
-
#new_line ⇒ String
readonly
The new line string, e.g.
-
#out ⇒ Object
readonly
The output string buffer.
-
#space_gen ⇒ Proc
readonly
Space generator, a callable.
-
#tokens ⇒ Array<Token>
readonly
The tokens list that is being built.
-
#whitespace ⇒ String
readonly
The whitespace character.
-
#width ⇒ Integer
readonly
Maximum line width.
Convenience Methods Built On {separate} collapse
-
#concat(*args, **kwargs) ⇒ Object
Concatenates args.
-
#lines(*args, **kwargs) ⇒ Object
Separate args into lines.
Convenience Methods Built On {surround} collapse
-
#angles(padding: '', **kwargs, &block) ⇒ self
#surround with
< >
. -
#angles_break_both(**kwargs) ⇒ self
#surround with
< >
. -
#angles_break_none(**kwargs) ⇒ self
#surround with
< >
. -
#backticks(**kwargs) ⇒ self
#surround with
` `
. -
#braces(padding: '', **kwargs, &block) ⇒ self
#surround with
{ }
. -
#braces_break_both(**kwargs) ⇒ self
#surround with
{ }
. -
#braces_break_none(**kwargs) ⇒ self
#surround with
{ }
. -
#brackets(padding: '', **kwargs, &block) ⇒ self
#surround with
[ ]
. -
#brackets_break_both(**kwargs) ⇒ self
#surround with
[ ]
. -
#brackets_break_none(**kwargs) ⇒ self
#surround with
[ ]
. -
#group_close ⇒ self
Close a group.
-
#group_open(break_type: :consistent, indent: 0) ⇒ self
Open a consistent group.
-
#indent_close(indent: @indent) ⇒ self
Close a group and subtract indent.
-
#indent_open(indent: @indent) ⇒ self
Open a consistent group and add indent amount.
-
#nest_close(indent: @indent) ⇒ self
Close a nest by subtracting indent.
-
#nest_open(indent: @indent) ⇒ self
Open a nest by adding indent.
-
#parens(padding: '', **kwargs, &block) ⇒ self
#surround with
( )
. -
#parens_break_both(**kwargs) ⇒ self
#surround with
( )
. -
#parens_break_none(**kwargs) ⇒ self
#surround with
( )
. -
#quote_double(**kwargs) ⇒ self
#surround with
" "
. -
#quote_single(**kwargs) ⇒ self
#surround with
' '
.
Instance Method Summary collapse
-
#add_missing_begin_and_end ⇒ Nil
Add missing Token::Begin, Token::End or Token::EOF.
-
#break(line_continuation: '') ⇒ self
Create a new break element.
-
#breakable(str = ' ', line_continuation: '', width: str.length) ⇒ self
Create a new breakable element.
-
#consistent ⇒ Object
An alias for
group(:consistent, ...)
. -
#do { ... } ⇒ self
A convenient way to avoid breaking chains of calls.
-
#group(break_type = :consistent, delim: nil, indent: @indent) { ... } ⇒ self
Create a new group.
-
#inconsistent ⇒ Object
An alias for
group(:inconsistent, ...)
. -
#initialize(base_indent: 0, config: Config.wadler, indent: 0, new_line: "\n", out: StringIO.new, space_gen: ' ', whitespace: ' ', width: 80) ⇒ Wadler
constructor
A new instance of Wadler.
-
#nest(delim: nil, indent: @indent) { ... } ⇒ self
Create a new non-strict #group.
-
#output ⇒ String
Call this to extract the final pretty-printed output.
-
#separate(args, sep, breakable: ' ', break_pos: :after, break_type: nil, indent: false, force_break: false, line_continuation: '') { ... } ⇒ self
Produce a separated list.
-
#show_print_commands(**kwargs) ⇒ String
Convert a list of tokens to its wadler representation.
-
#space ⇒ self
A shorhand for
text ' '
. -
#surround(lft, rgt, **opts) { ... } ⇒ self
Surround a block with +lft+ and +rgt+.
-
#text(value, width: value.length) ⇒ self
Create a new text element.
-
#wrap(&blk) ⇒ Wrap
A means to wrap a piece of code in several ways.
Constructor Details
#initialize(base_indent: 0, config: Config.wadler, indent: 0, new_line: "\n", out: StringIO.new, space_gen: ' ', whitespace: ' ', width: 80) ⇒ Wadler
Returns a new instance of Wadler.
51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/wadler/print.rb', line 51 def initialize(base_indent: 0, config: Config.wadler, indent: 0, new_line: "\n", out: StringIO.new, space_gen: ' ', whitespace: ' ', width: 80) @config = config @current_indent = base_indent @indent = indent @new_line = new_line @out = out @space_gen = space_gen @tokens = [] @whitespace = whitespace @width = width end |
Instance Attribute Details
#config ⇒ Config (readonly)
Returns The printer's configuration, altering its behavior.
9 10 11 |
# File 'lib/wadler/print.rb', line 9 def config @config end |
#current_indent ⇒ Integer (readonly)
Returns the current indentation amount.
12 13 14 |
# File 'lib/wadler/print.rb', line 12 def current_indent @current_indent end |
#new_line ⇒ String (readonly)
Returns the new line string, e.g. \n
.
15 16 17 |
# File 'lib/wadler/print.rb', line 15 def new_line @new_line end |
#out ⇒ Object (readonly)
Returns the output string buffer. It should have a write
and string
methods.
18 19 20 |
# File 'lib/wadler/print.rb', line 18 def out @out end |
#space_gen ⇒ Proc (readonly)
Returns space generator, a callable.
21 22 23 |
# File 'lib/wadler/print.rb', line 21 def space_gen @space_gen end |
#tokens ⇒ Array<Token> (readonly)
Returns the tokens list that is being built.
24 25 26 |
# File 'lib/wadler/print.rb', line 24 def tokens @tokens end |
#whitespace ⇒ String (readonly)
Returns the whitespace character. Used to trim trailing whitespaces.
27 28 29 |
# File 'lib/wadler/print.rb', line 27 def whitespace @whitespace end |
#width ⇒ Integer (readonly)
Returns maximum line width.
30 31 32 |
# File 'lib/wadler/print.rb', line 30 def width @width end |
Instance Method Details
#add_missing_begin_and_end ⇒ Nil
Add missing Token::Begin, Token::End or Token::EOF.
68 69 70 71 72 |
# File 'lib/wadler/print.rb', line 68 def add_missing_begin_and_end tokens.unshift Oppen.begin_consistent(offset: 0) tokens << Oppen.end tokens << Oppen.eof if !tokens.last.is_a?(Oppen::Token::EOF) end |
#angles(padding: '', **kwargs, &block) ⇒ self
#surround with < >
. New lines can appear after and before the delimiters.
632 633 634 635 636 637 638 |
# File 'lib/wadler/print.rb', line 632 def angles(padding: '', **kwargs, &block) surround( '<', '>', **kwargs.merge(lft_breakable: padding, rgt_breakable: padding), &block ) end |
#angles_break_both(**kwargs) ⇒ self
#surround with < >
. New lines cannot appear after and before the delimiters.
643 644 645 |
# File 'lib/wadler/print.rb', line 643 def angles_break_both(**kwargs, &) angles(**kwargs.merge(lft_force_break: true, rgt_force_break: true), &) end |
#angles_break_none(**kwargs) ⇒ self
#surround with < >
. New lines will appear after and before the delimiters.
650 651 652 |
# File 'lib/wadler/print.rb', line 650 def angles_break_none(**kwargs, &) angles(**kwargs.merge(lft_can_break: false, rgt_can_break: false), &) end |
#backticks(**kwargs) ⇒ self
#surround with ` `
. New lines cannot appear after and before the delimiters
unless you specify it with rgt_can_break
and lft_can_break
.
742 743 744 |
# File 'lib/wadler/print.rb', line 742 def backticks(**kwargs, &) surround('`', '`', lft_can_break: false, rgt_can_break: false, **kwargs, &) end |
#braces(padding: '', **kwargs, &block) ⇒ self
#surround with { }
. New lines can appear after and before the delimiters.
660 661 662 663 664 665 666 |
# File 'lib/wadler/print.rb', line 660 def braces(padding: '', **kwargs, &block) surround( '{', '}', **kwargs.merge(lft_breakable: padding, rgt_breakable: padding), &block ) end |
#braces_break_both(**kwargs) ⇒ self
#surround with { }
. New lines cannot appear after and before the delimiters.
671 672 673 |
# File 'lib/wadler/print.rb', line 671 def braces_break_both(**kwargs, &) braces(**kwargs.merge(lft_force_break: true, rgt_force_break: true), &) end |
#braces_break_none(**kwargs) ⇒ self
#surround with { }
. New lines will appear after and before the delimiters.
678 679 680 |
# File 'lib/wadler/print.rb', line 678 def braces_break_none(**kwargs, &) braces(**kwargs.merge(lft_can_break: false, rgt_can_break: false), &) end |
#brackets(padding: '', **kwargs, &block) ⇒ self
#surround with [ ]
. New lines can appear after and before the delimiters.
688 689 690 691 692 693 694 |
# File 'lib/wadler/print.rb', line 688 def brackets(padding: '', **kwargs, &block) surround( '[', ']', **kwargs.merge(lft_breakable: padding, rgt_breakable: padding), &block ) end |
#brackets_break_both(**kwargs) ⇒ self
#surround with [ ]
. New lines cannot appear after and before the delimiters.
699 700 701 |
# File 'lib/wadler/print.rb', line 699 def brackets_break_both(**kwargs, &) brackets(**kwargs.merge(lft_force_break: true, rgt_force_break: true), &) end |
#brackets_break_none(**kwargs) ⇒ self
#surround with [ ]
. New lines will appear after and before the delimiters.
706 707 708 |
# File 'lib/wadler/print.rb', line 706 def brackets_break_none(**kwargs, &) brackets(**kwargs.merge(lft_can_break: false, rgt_can_break: false), &) end |
#break(line_continuation: '') ⇒ self
Create a new break element.
375 376 377 378 379 380 381 |
# File 'lib/wadler/print.rb', line 375 def break(line_continuation: '') if line_continuation && config.trim_trailing_whitespaces? line_continuation = line_continuation.sub(/(?:#{Regexp.escape(whitespace)})+\z/, '') end tokens << Oppen.line_break(line_continuation:, offset: current_indent) self end |
#breakable(str = ' ', line_continuation: '', width: str.length) ⇒ self
Create a new breakable element.
347 348 349 350 351 352 353 |
# File 'lib/wadler/print.rb', line 347 def breakable(str = ' ', line_continuation: '', width: str.length) if config.trim_trailing_whitespaces? && line_continuation line_continuation = line_continuation.sub(/(?:#{Regexp.escape(whitespace)})+\z/, '') end tokens << Oppen.break(str, width:, line_continuation:, offset: current_indent) self end |
#concat(*args, **kwargs) ⇒ Object
Concatenates args.
This is a wrapper around #separate where breakable: false
.
616 617 618 |
# File 'lib/wadler/print.rb', line 616 def concat(*args, **kwargs, &) separate(*args, **kwargs.merge(breakable: false), &) end |
#consistent ⇒ Object
An alias for group(:consistent, ...)
237 238 239 |
# File 'lib/wadler/print.rb', line 237 def consistent(...) group(:consistent, ...) end |
#do { ... } ⇒ self
A convenient way to avoid breaking chains of calls.
396 397 398 399 |
# File 'lib/wadler/print.rb', line 396 def do yield self end |
#group(break_type = :consistent, delim: nil, indent: @indent) { ... } ⇒ self
Create a new group.
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/wadler/print.rb', line 203 def group(break_type = :consistent, delim: nil, indent: @indent) lft, rgt = case delim in nil then ['', ''] in String | Symbol then [delim, delim] in Array then delim.values_at(0, 1).map(&:to_s) end tokens << case break_type in :consistent Oppen.begin_consistent(offset: indent) in :inconsistent Oppen.begin_inconsistent(offset: indent) end if !lft.empty? self.break text lft end yield if !rgt.empty? self.break text rgt end tokens << Oppen.end self end |
#group_close ⇒ self
Close a group.
785 786 787 788 |
# File 'lib/wadler/print.rb', line 785 def group_close tokens << Oppen.end self end |
#group_open(break_type: :consistent, indent: 0) ⇒ self
Open a consistent group.
773 774 775 776 777 778 779 780 |
# File 'lib/wadler/print.rb', line 773 def group_open(break_type: :consistent, indent: 0) if %i[consistent inconsistent].none?(break_type) raise ArgumentError, '%s is not a valid type. Choose one: :consistent or :inconsistent' end tokens << Oppen.send(:"begin_#{break_type}", offset: indent) self end |
#inconsistent ⇒ Object
An alias for group(:inconsistent, ...)
242 243 244 |
# File 'lib/wadler/print.rb', line 242 def inconsistent(...) group(:inconsistent, ...) end |
#indent_close(indent: @indent) ⇒ self
Close a group and subtract indent.
807 808 809 810 |
# File 'lib/wadler/print.rb', line 807 def indent_close(indent: @indent) @current_indent -= indent group_close end |
#indent_open(indent: @indent) ⇒ self
Open a consistent group and add indent amount.
796 797 798 799 |
# File 'lib/wadler/print.rb', line 796 def indent_open(indent: @indent) @current_indent += indent group_open end |
#lines(*args, **kwargs) ⇒ Object
Separate args into lines.
This is a wrapper around #separate where breakable: true
.
607 608 609 |
# File 'lib/wadler/print.rb', line 607 def lines(*args, **kwargs, &) separate(*args, **kwargs.merge(force_break: true), &) end |
#nest(delim: nil, indent: @indent) { ... } ⇒ self
indentation cannot happen if there are no breaks in the #nest.
a #nest will not forcibly indent its content if the break type of
Create a new non-strict #group.
#groups isolate breaking decisions, and in that sense they're considered strict; e.g. when a breakable is transformed into an actual break, its parent #group might not get broken if the result could fit on the line.
This is not the case with #nest: if the same breakable was in a #nest, the #group containing the #nest will also be broken.
the enclosing #group is :inconsistent
.
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/wadler/print.rb', line 286 def nest(delim: nil, indent: @indent) lft, rgt = case delim in nil then ['', ''] in String | Symbol then [delim, delim] in Array then delim.values_at(0, 1).map(&:to_s) end @current_indent += indent if !lft.empty? text lft self.break end begin yield ensure @current_indent -= indent end if !rgt.empty? self.break text rgt end self end |
#nest_close(indent: @indent) ⇒ self
Close a nest by subtracting indent.
829 830 831 832 |
# File 'lib/wadler/print.rb', line 829 def nest_close(indent: @indent) @current_indent -= indent self end |
#nest_open(indent: @indent) ⇒ self
Open a nest by adding indent.
818 819 820 821 |
# File 'lib/wadler/print.rb', line 818 def nest_open(indent: @indent) @current_indent += indent self end |
#output ⇒ String
Call this to extract the final pretty-printed output.
77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/wadler/print.rb', line 77 def output add_missing_begin_and_end Oppen.print( tokens:, new_line:, config:, space: space_gen, out:, width:, ) end |
#parens(padding: '', **kwargs, &block) ⇒ self
#surround with ( )
. New lines can appear after and before the delimiters.
716 717 718 719 720 721 722 |
# File 'lib/wadler/print.rb', line 716 def parens(padding: '', **kwargs, &block) surround( '(', ')', **kwargs.merge(lft_breakable: padding, rgt_breakable: padding), &block ) end |
#parens_break_both(**kwargs) ⇒ self
#surround with ( )
. New lines cannot appear after and before the delimiters.
727 728 729 |
# File 'lib/wadler/print.rb', line 727 def parens_break_both(**kwargs, &) parens(**kwargs.merge(lft_force_break: true, rgt_force_break: true), &) end |
#parens_break_none(**kwargs) ⇒ self
#surround with ( )
. New lines will appear after and before the delimiters.
734 735 736 |
# File 'lib/wadler/print.rb', line 734 def parens_break_none(**kwargs, &) parens(**kwargs.merge(lft_can_break: false, rgt_can_break: false), &) end |
#quote_double(**kwargs) ⇒ self
#surround with " "
. New lines cannot appear after and before the delimiters
unless you specify it with rgt_can_break
and lft_can_break
.
750 751 752 |
# File 'lib/wadler/print.rb', line 750 def quote_double(**kwargs, &) surround('"', '"', lft_can_break: false, rgt_can_break: false, **kwargs, &) end |
#quote_single(**kwargs) ⇒ self
#surround with ' '
. New lines cannot appear after and before the delimiters
unless you specify it with rgt_can_break
and lft_can_break
.
758 759 760 |
# File 'lib/wadler/print.rb', line 758 def quote_single(**kwargs, &) surround("'", "'", lft_can_break: false, rgt_can_break: false, **kwargs, &) end |
#separate(args, sep, breakable: ' ', break_pos: :after, break_type: nil, indent: false, force_break: false, line_continuation: '') { ... } ⇒ self
Produce a separated list.
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 |
# File 'lib/wadler/print.rb', line 475 def separate(args, sep, breakable: ' ', break_pos: :after, break_type: nil, indent: false, force_break: false, line_continuation: '') if args.is_a?(Enumerator) ? args.count == 1 : args.length == 1 yield(*args[0]) return self end first = true wrap { wrap { args&.each do |*as| if first breakable '' if !line_continuation.empty? && break_pos == :after first = false elsif break_pos == :after text sep breakable(breakable, line_continuation:) if breakable && !force_break self.break(line_continuation:) if force_break else breakable(breakable, line_continuation:) if breakable && !force_break self.break(line_continuation:) if force_break text sep end yield(*as) end } .when(break_type) { |body| group(break_type, indent: 0) { body.() } } .end } .when(indent) { |body| nest(indent: indent.is_a?(Integer) ? indent : @indent) { body.() } }.end breakable('', line_continuation:) if !line_continuation.empty? && !break_type self end |
#show_print_commands(**kwargs) ⇒ String
Convert a list of tokens to its wadler representation.
This method reverse engineers a tokens list to transform it into Wadler printing commands. It can be particularly useful when debugging a black box program.
111 112 113 114 |
# File 'lib/wadler/print.rb', line 111 def show_print_commands(**kwargs) add_missing_begin_and_end Oppen.tokens_to_wadler(tokens, **kwargs) end |
#space ⇒ self
A shorhand for text ' '
.
522 523 524 |
# File 'lib/wadler/print.rb', line 522 def space text ' ' end |
#surround(lft, rgt, **opts) { ... } ⇒ self
Surround a block with +lft+ and +rgt+
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
# File 'lib/wadler/print.rb', line 555 def surround(lft, rgt, **opts) group = opts.fetch(:group, true) group_open(break_type: :inconsistent) if group text lft if lft indent = opts.fetch(:indent, @indent) nest_open(indent:) lft_breakable = opts.fetch(:lft_breakable, '') lft_can_break = opts.fetch(:lft_can_break, true) lft_force_break = opts.fetch(:lft_force_break, false) if lft && lft_can_break if lft_force_break self.break else breakable lft_breakable end end if block_given? yield end nest_close rgt_breakable = opts.fetch(:rgt_breakable, '') rgt_can_break = opts.fetch(:rgt_can_break, true) rgt_force_break = opts.fetch(:rgt_force_break, false) if rgt if rgt_can_break if rgt_force_break self.break else breakable rgt_breakable end end text rgt end group_close if group self end |
#text(value, width: value.length) ⇒ self
Create a new text element.
321 322 323 324 325 326 327 328 329 330 331 332 333 |
# File 'lib/wadler/print.rb', line 321 def text(value, width: value.length) if config.trim_trailing_whitespaces? && value.match(/((?:#{Regexp.escape(whitespace)})+)\z/) match = Regexp.last_match(1) matched_length = match.length if value.length != matched_length tokens << Oppen.string(value[0...-matched_length], width: width - matched_length) end tokens << Oppen.whitespace(match) else tokens << Oppen.string(value, width:) end self end |