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.
626 627 628 629 630 631 632 |
# File 'lib/wadler/print.rb', line 626 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.
637 638 639 |
# File 'lib/wadler/print.rb', line 637 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.
644 645 646 |
# File 'lib/wadler/print.rb', line 644 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
.
736 737 738 |
# File 'lib/wadler/print.rb', line 736 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.
654 655 656 657 658 659 660 |
# File 'lib/wadler/print.rb', line 654 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.
665 666 667 |
# File 'lib/wadler/print.rb', line 665 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.
672 673 674 |
# File 'lib/wadler/print.rb', line 672 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.
682 683 684 685 686 687 688 |
# File 'lib/wadler/print.rb', line 682 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.
693 694 695 |
# File 'lib/wadler/print.rb', line 693 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.
700 701 702 |
# File 'lib/wadler/print.rb', line 700 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.
372 373 374 375 |
# File 'lib/wadler/print.rb', line 372 def break(line_continuation: '') 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 |
# File 'lib/wadler/print.rb', line 347 def breakable(str = ' ', line_continuation: '', width: str.length) 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
.
610 611 612 |
# File 'lib/wadler/print.rb', line 610 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.
390 391 392 393 |
# File 'lib/wadler/print.rb', line 390 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.
779 780 781 782 |
# File 'lib/wadler/print.rb', line 779 def group_close tokens << Oppen.end self end |
#group_open(break_type: :consistent, indent: 0) ⇒ self
Open a consistent group.
767 768 769 770 771 772 773 774 |
# File 'lib/wadler/print.rb', line 767 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.
801 802 803 804 |
# File 'lib/wadler/print.rb', line 801 def indent_close(indent: @indent) @current_indent -= indent group_close end |
#indent_open(indent: @indent) ⇒ self
Open a consistent group and add indent amount.
790 791 792 793 |
# File 'lib/wadler/print.rb', line 790 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
.
601 602 603 |
# File 'lib/wadler/print.rb', line 601 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.
823 824 825 826 |
# File 'lib/wadler/print.rb', line 823 def nest_close(indent: @indent) @current_indent -= indent self end |
#nest_open(indent: @indent) ⇒ self
Open a nest by adding indent.
812 813 814 815 |
# File 'lib/wadler/print.rb', line 812 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.
710 711 712 713 714 715 716 |
# File 'lib/wadler/print.rb', line 710 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.
721 722 723 |
# File 'lib/wadler/print.rb', line 721 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.
728 729 730 |
# File 'lib/wadler/print.rb', line 728 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
.
744 745 746 |
# File 'lib/wadler/print.rb', line 744 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
.
752 753 754 |
# File 'lib/wadler/print.rb', line 752 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.
469 470 471 472 473 474 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 |
# File 'lib/wadler/print.rb', line 469 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 ' '
.
516 517 518 |
# File 'lib/wadler/print.rb', line 516 def space text ' ' end |
#surround(lft, rgt, **opts) { ... } ⇒ self
Surround a block with +lft+ and +rgt+
549 550 551 552 553 554 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 |
# File 'lib/wadler/print.rb', line 549 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 |