oppen 0.9.7 → 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  - - ">="