oppen 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
data/lib/wadler/print.rb CHANGED
@@ -4,30 +4,49 @@
4
4
  module Oppen
5
5
  # Wadler.
6
6
  class Wadler
7
+ # @return [Config]
8
+ # The printer's configuration, altering its behavior.
7
9
  attr_reader :config
10
+ # @return [Integer]
11
+ # the current indentation amount.
8
12
  attr_reader :current_indent
9
- attr_reader :space
13
+ # @return [String]
14
+ # the new line string, e.g. `\n`.
10
15
  attr_reader :new_line
16
+ # @return [Object]
17
+ # the output string buffer. It should have a `write` and `string` methods.
11
18
  attr_reader :out
19
+ # @return [Proc]
20
+ # space generator, a callable.
21
+ attr_reader :space
22
+ # @return [Array<Token>]
23
+ # the tokens list that is being built.
12
24
  attr_reader :tokens
25
+ # @return [String]
26
+ # the whitespace character. Used to trim trailing whitespaces.
13
27
  attr_reader :whitespace
28
+ # @return [Integer]
29
+ # maximum line width.
14
30
  attr_reader :width
15
31
 
16
- # @param config [Oppen::Config]
17
- # @param space [String, Proc] could be a String or a callable.
18
- # If it's a string, spaces will be generated with the the
19
- # lambda `->(n){ n * space }`, where `n` is the number of columns
20
- # to indent.
21
- # If it's a callable, it will receive `n` and it needs to return
22
- # a string.
23
- # @param new_line [String]
24
- # @param out [Object] should have a write and string method
25
- # @param width [Integer]
26
- # @param whitespace [String] the whitespace character. Used to trim trailing whitespaces.
32
+ # @param config [Config]
33
+ # to customize the printer's behavior.
34
+ # @param new_line [String]
35
+ # the new line String.
36
+ # @param out [Object]
37
+ # the output string buffer. It should have a `write` and `string` methods.
38
+ # @param space [String, Proc]
39
+ # indentation string or a string generator.
40
+ # - If a `String`, spaces will be generated with the the lambda
41
+ # `->(n){ space * n }`, where `n` is the number of columns to indent.
42
+ # - If a `Proc`, it will receive `n` and it needs to return a `String`.
43
+ # @param whitespace [String] the whitespace character. Used to trim trailing whitespaces.
44
+ # @param width [Integer] maximum line width desired.
45
+ #
27
46
  # @see Token::Whitespace
28
- def initialize(config: Config.wadler, space: ' ',
29
- new_line: "\n", out: StringIO.new,
30
- width: 80, whitespace: ' ')
47
+ def initialize(config: Config.wadler, new_line: "\n",
48
+ out: StringIO.new, space: ' ',
49
+ whitespace: ' ', width: 80)
31
50
  @config = config
32
51
  @current_indent = 0
33
52
  @space = space
@@ -38,7 +57,8 @@ module Oppen
38
57
  @whitespace = whitespace
39
58
  end
40
59
 
41
- # Add missing Begin, End or EOF tokens.
60
+ # Add missing {Token::Begin}, {Token::End} or {Token::EOF}.
61
+ #
42
62
  # @return [Nil]
43
63
  def add_missing_begin_and_end
44
64
  if !tokens.first.is_a? Token::Begin
@@ -48,42 +68,124 @@ module Oppen
48
68
  tokens << Oppen.eof if !tokens.last.is_a?(Oppen::Token::EOF)
49
69
  end
50
70
 
51
- # Generate the output string of the built list of tokens
52
- # using Oppen's pretty printing algorithm.
71
+ # Call this to extract the final pretty-printed output.
53
72
  #
54
73
  # @return [String]
55
74
  def output
56
75
  add_missing_begin_and_end
57
- Oppen.print(tokens:, new_line:, config:, space:, out:, width:)
76
+ Oppen.print(
77
+ tokens: tokens,
78
+ new_line: new_line,
79
+ config: config,
80
+ space: space,
81
+ out: out,
82
+ width: width,
83
+ )
58
84
  end
59
85
 
60
- # Generate the the list of Wadler commands needed to build the built
61
- # list of tokens.
86
+ # Convert a list of tokens to its wadler representation.
87
+ #
88
+ # This method reverse engineers a tokens list to transform it into Wadler
89
+ # printing commands. It can be particularly useful when debugging a black
90
+ # box program.
91
+ #
92
+ # @option kwargs [Integer] :base_indent
93
+ # the base indentation amount of the output.
94
+ # @option kwargs [String] :printer_name
95
+ # the name of the Wadler instance in the output.
96
+ #
97
+ # @example
98
+ # out = Oppen::Wadler.new
99
+ # out.group {
100
+ # out.text('Hello World!')
101
+ # }
102
+ # out.show_print_commands(out_name: 'out')
103
+ #
104
+ # # =>
105
+ # # out.group(0, "", "", :consistent) {
106
+ # # out.text("Hello World!", width: 12)
107
+ # # }
62
108
  #
63
109
  # @return [String]
64
- def show_print_commands(**)
110
+ def show_print_commands(**kwargs)
65
111
  add_missing_begin_and_end
66
- Oppen.tokens_to_wadler(tokens, **)
112
+ Oppen.tokens_to_wadler(tokens, **kwargs)
67
113
  end
68
114
 
69
- # @param indent [Integer] group indentation
70
- # @param open_obj [String] group opening delimiter
71
- # @param close_obj [String] group closing delimiter
72
- # @param break_type [Oppen::Token::BreakType] group breaking type
115
+ # Create a new group.
116
+ #
117
+ # @param indent [Integer]
118
+ # indentation.
119
+ # @param open_obj [String]
120
+ # opening delimiter.
121
+ # @param close_obj [String]
122
+ # closing delimiter.
123
+ # @param break_type [Token::BreakType]
124
+ # break type.
125
+ #
126
+ # @yield
127
+ # the block of text in a group.
128
+ #
129
+ # @example
130
+ # out = Oppen::Wadler.new
131
+ # out.text 'a'
132
+ # out.group(2, '{', '}') {
133
+ # out.break
134
+ # out.text 'b'
135
+ # }
136
+ # out.output
137
+ #
138
+ # # =>
139
+ # # a
140
+ # # {
141
+ # # b
142
+ # # }
143
+ #
144
+ # @example Consistent Breaking
145
+ # out = Oppen::Wadler.new
146
+ # out.group(0, '', '', :consistent) {
147
+ # out.text 'a'
148
+ # out.break
149
+ # out.text 'b'
150
+ # out.breakable
151
+ # out.text 'c'
152
+ # }
153
+ # out.output
154
+ #
155
+ # # =>
156
+ # # a
157
+ # # b
158
+ # # c
159
+ #
160
+ # @example Inconsistent Breaking
161
+ # out = Oppen::Wadler.new
162
+ # out.group(0, '', '', :inconsistent) {
163
+ # out.text 'a'
164
+ # out.break
165
+ # out.text 'b'
166
+ # out.breakable
167
+ # out.text 'c'
168
+ # }
169
+ # out.output
73
170
  #
74
- # @yield the block of text in a group
171
+ # # =>
172
+ # # a
173
+ # # b c
75
174
  #
76
175
  # @return [Nil]
176
+ #
177
+ # @see Oppen.begin_consistent
178
+ # @see Oppen.begin_inconsistent
77
179
  def group(indent = 0, open_obj = '', close_obj = '',
78
- break_type = Oppen::Token::BreakType::CONSISTENT)
180
+ break_type = :consistent)
79
181
  raise ArgumentError, "#{open_obj.nil? ? 'open_obj' : 'close_obj'} cannot be nil" \
80
182
  if open_obj.nil? || close_obj.nil?
81
183
 
82
184
  tokens <<
83
185
  case break_type
84
- in Oppen::Token::BreakType::CONSISTENT
186
+ in :consistent
85
187
  Oppen.begin_consistent(offset: indent)
86
- in Oppen::Token::BreakType::INCONSISTENT
188
+ in :inconsistent
87
189
  Oppen.begin_inconsistent(offset: indent)
88
190
  end
89
191
 
@@ -102,9 +204,44 @@ module Oppen
102
204
  tokens << Oppen.end
103
205
  end
104
206
 
105
- # @param indent [Integer] nest indentation
106
- # @param open_obj [String] nest opening delimiter
107
- # @param close_obj [String] nest closing delimiter
207
+ # Create a new non-strict {group}.
208
+ #
209
+ # {group}s isolate breaking decisions, and in that sense they're considered
210
+ # strict; e.g. when a breakable is transformed into an actual break, its
211
+ # parent {group} might not get broken if the result could fit on the line.
212
+ #
213
+ # This is not the case with {nest}: if the same breakable was in a {nest}, the
214
+ # {group} containing the {nest} will also be broken.
215
+ #
216
+ # @note indentation cannot happen if there are no breaks in the {nest}.
217
+ #
218
+ # @note a {nest} will not forcibly indent its content if the break type of
219
+ # the enclosing {group} is `:inconsistent`.
220
+ #
221
+ # @param indent [Integer]
222
+ # indentation.
223
+ # @param open_obj [String]
224
+ # opening delimiter. A {break} is implicitly slipped after it if it's not empty.
225
+ # @param close_obj [String]
226
+ # closing delimiter. A {break} is implicitly slipped before it if it's not empty.
227
+ #
228
+ # @yield
229
+ # the block of text in a nest.
230
+ #
231
+ # @example
232
+ # out = Oppen::Wadler.new
233
+ # out.nest(2, '{', '}') {
234
+ # out.text 'a'
235
+ # out.break
236
+ # out.text 'b'
237
+ # }
238
+ # out.output
239
+ #
240
+ # # =>
241
+ # # {
242
+ # # a
243
+ # # b
244
+ # # }
108
245
  #
109
246
  # @return [Nil]
110
247
  def nest(indent, open_obj = '', close_obj = '')
@@ -130,7 +267,10 @@ module Oppen
130
267
  text(close_obj)
131
268
  end
132
269
 
270
+ # Create a new text element.
271
+ #
133
272
  # @param value [String]
273
+ # the value of the token.
134
274
  #
135
275
  # @return [Nil]
136
276
  def text(value, width: value.length)
@@ -142,30 +282,56 @@ module Oppen
142
282
  end
143
283
  tokens << Oppen.whitespace(match)
144
284
  else
145
- tokens << Oppen.string(value, width:)
285
+ tokens << Oppen.string(value, width: width)
146
286
  end
147
287
  end
148
288
 
149
- # @param str [String]
150
- # @param line_continuation [String] If a new line is needed display this string before the new line
289
+ # Create a new breakable element.
290
+ #
291
+ # @param str [String]
292
+ # the value of the token that will be displayed if no new line is needed.
293
+ # @param line_continuation [String]
294
+ # printed before the line break.
295
+ # @param width [Integer]
296
+ # the width of the token.
151
297
  #
152
298
  # @return [Nil]
153
- def breakable(str = ' ', width: str.length, line_continuation: '')
154
- tokens << Oppen.break(str, width:, line_continuation:, offset: current_indent)
299
+ #
300
+ # @see Wadler#break example on `line_continuation`.
301
+ def breakable(str = ' ', line_continuation: '', width: str.length)
302
+ tokens << Oppen.break(str, width: width, line_continuation: line_continuation, offset: current_indent)
155
303
  end
156
304
 
157
- # @param line_continuation [String] If a new line is needed display this string before the new line
305
+ # Create a new break element.
306
+ #
307
+ # @param line_continuation [String]
308
+ # printed before the line break.
309
+ #
310
+ # @example
311
+ # out = Oppen::Wadler.new
312
+ # out.text 'a'
313
+ # out.break
314
+ # out.text 'b'
315
+ # out.break line_continuation: '#'
316
+ # out.text 'c'
317
+ # out.output
318
+ #
319
+ # # =>
320
+ # # a
321
+ # # b#
322
+ # # c
158
323
  #
159
324
  # @return [Nil]
160
325
  def break(line_continuation: '')
161
- tokens << Oppen.line_break(line_continuation:, offset: current_indent)
326
+ tokens << Oppen.line_break(line_continuation: line_continuation, offset: current_indent)
162
327
  end
163
328
 
164
329
  # @!group Helpers
165
330
 
166
- # Set a base indenetaion level to the printer.
331
+ # Set a base indenetaion level for the printer.
167
332
  #
168
333
  # @param indent [Integer]
334
+ # the amount of indentation.
169
335
  #
170
336
  # @return [Nil]
171
337
  def base_indent(indent = 0)
@@ -175,9 +341,14 @@ module Oppen
175
341
  # Open a consistent group.
176
342
  #
177
343
  # @param inconsistent [Boolean]
344
+ # whether the break type of the group should be inconsistent.
178
345
  # @param indent [Integer]
346
+ # the amount of indentation of the group.
179
347
  #
180
348
  # @return [Nil]
349
+ #
350
+ # @see Oppen.begin_consistent
351
+ # @see Oppen.begin_inconsistent
181
352
  def group_open(inconsistent: false, indent: 0)
182
353
  tokens <<
183
354
  if inconsistent
@@ -194,9 +365,10 @@ module Oppen
194
365
  tokens << Oppen.end
195
366
  end
196
367
 
197
- # Open a consistent group with indent.
368
+ # Open a consistent group and add indent amount.
198
369
  #
199
370
  # @param indent [Integer]
371
+ # the amount of indentation of the group.
200
372
  #
201
373
  # @return [Nil]
202
374
  def indent_open(indent)
@@ -204,9 +376,10 @@ module Oppen
204
376
  group_open
205
377
  end
206
378
 
207
- # Close a group with indent.
379
+ # Close a group and subtract indent.
208
380
  #
209
381
  # @param indent [Integer]
382
+ # the amount of indentation of the group.
210
383
  #
211
384
  # @return [Nil]
212
385
  def indent_close(group, indent)
@@ -214,18 +387,20 @@ module Oppen
214
387
  group_close(group)
215
388
  end
216
389
 
217
- # Open a nest by indent.
390
+ # Open a nest by adding indent.
218
391
  #
219
392
  # @param indent [Integer]
393
+ # the amount of indentation of the nest.
220
394
  #
221
395
  # @return [Nil]
222
396
  def nest_open(indent)
223
397
  @current_indent += indent
224
398
  end
225
399
 
226
- # Close a nest by indent.
400
+ # Close a nest by subtracting indent.
227
401
  #
228
402
  # @param indent [Integer]
403
+ # the amount of indentation of the nest.
229
404
  #
230
405
  # @return [Nil]
231
406
  def nest_close(indent)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oppen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amine Mike El Maalouf <amine.el-maalouf@epita.fr>
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-12-05 00:00:00.000000000 Z
12
+ date: 2024-12-30 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Implementation of the Oppen's pretty printing algorithm
15
15
  email:
@@ -37,9 +37,9 @@ require_paths:
37
37
  - lib
38
38
  required_ruby_version: !ruby/object:Gem::Requirement
39
39
  requirements:
40
- - - "~>"
40
+ - - ">="
41
41
  - !ruby/object:Gem::Version
42
- version: '3.2'
42
+ version: '3.0'
43
43
  required_rubygems_version: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="