nrser 0.1.4 → 0.2.0.pre.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nrser.rb +3 -0
  3. data/lib/nrser/char.rb +2 -3
  4. data/lib/nrser/char/alpha_numeric_sub.rb +233 -0
  5. data/lib/nrser/ext.rb +1 -0
  6. data/lib/nrser/ext/binding.rb +36 -0
  7. data/lib/nrser/ext/string.rb +29 -0
  8. data/lib/nrser/functions/binding.rb +40 -15
  9. data/lib/nrser/functions/string.rb +17 -1
  10. data/lib/nrser/functions/string/style.rb +71 -0
  11. data/lib/nrser/mean_streak.rb +33 -8
  12. data/lib/nrser/mean_streak/document.rb +221 -36
  13. data/lib/nrser/refinements/binding.rb +3 -4
  14. data/lib/nrser/rspex.rb +3 -17
  15. data/lib/nrser/rspex/example.rb +49 -0
  16. data/lib/nrser/rspex/example_group.rb +61 -33
  17. data/lib/nrser/rspex/example_group/describe_called_with.rb +42 -0
  18. data/lib/nrser/rspex/example_group/describe_spec_file.rb +2 -0
  19. data/lib/nrser/rspex/format.rb +48 -78
  20. data/lib/nrser/types.rb +71 -14
  21. data/lib/nrser/types/attrs.rb +121 -110
  22. data/lib/nrser/types/bounded.rb +3 -2
  23. data/lib/nrser/types/combinators.rb +39 -8
  24. data/lib/nrser/types/hashes.rb +5 -4
  25. data/lib/nrser/types/is.rb +11 -1
  26. data/lib/nrser/types/is_a.rb +11 -2
  27. data/lib/nrser/types/maybe.rb +4 -5
  28. data/lib/nrser/types/nil.rb +1 -10
  29. data/lib/nrser/types/not.rb +53 -0
  30. data/lib/nrser/types/numbers.rb +20 -17
  31. data/lib/nrser/types/shape.rb +75 -0
  32. data/lib/nrser/types/strings.rb +49 -59
  33. data/lib/nrser/types/symbols.rb +13 -18
  34. data/lib/nrser/types/type.rb +32 -9
  35. data/lib/nrser/types/when.rb +102 -0
  36. data/lib/nrser/version.rb +1 -1
  37. data/spec/{nrser → lib/nrser}/collection/each_spec.rb +0 -0
  38. data/spec/{nrser → lib/nrser}/collection/map_spec.rb +0 -0
  39. data/spec/{nrser → lib/nrser}/env/path/insert_spec.rb +0 -0
  40. data/spec/{nrser → lib/nrser}/env/path_spec.rb +0 -0
  41. data/spec/{nrser → lib/nrser}/errors/abstract_method_error_spec.rb +0 -0
  42. data/spec/{nrser → lib/nrser}/functions/binding/template_spec.rb +0 -0
  43. data/spec/{nrser → lib/nrser}/functions/enumerable/find_all_map_spec.rb +0 -0
  44. data/spec/{nrser → lib/nrser}/functions/enumerable/find_bounded_spec.rb +0 -0
  45. data/spec/{nrser → lib/nrser}/functions/enumerable/find_map_spec.rb +0 -0
  46. data/spec/{nrser → lib/nrser}/functions/enumerable/find_only_spec.rb +0 -0
  47. data/spec/{nrser → lib/nrser}/functions/enumerable/include_slice_spec.rb +0 -0
  48. data/spec/{nrser → lib/nrser}/functions/enumerable/to_h_by_spec.rb +0 -0
  49. data/spec/{nrser → lib/nrser}/functions/exception/format_exception_spec.rb +0 -0
  50. data/spec/{nrser → lib/nrser}/functions/hash/bury_spec.rb +0 -0
  51. data/spec/{nrser → lib/nrser}/functions/hash/guess_label_key_type_spec.rb +0 -0
  52. data/spec/{nrser → lib/nrser}/functions/hash_spec.rb +0 -0
  53. data/spec/{nrser → lib/nrser}/functions/merge_by_spec.rb +0 -0
  54. data/spec/{nrser → lib/nrser}/functions/object/truthy_spec.rb +0 -0
  55. data/spec/{nrser → lib/nrser}/functions/open_struct_spec.rb +0 -0
  56. data/spec/{nrser → lib/nrser}/functions/string/common_prefix_spec.rb +0 -0
  57. data/spec/{nrser → lib/nrser}/functions/string/looks_like_spec.rb +0 -0
  58. data/spec/{nrser → lib/nrser}/functions/string/truncate_spec.rb +0 -0
  59. data/spec/{nrser → lib/nrser}/functions/text/dedent/gotchas_spec.rb +0 -0
  60. data/spec/{nrser → lib/nrser}/functions/text/dedent_spec.rb +0 -0
  61. data/spec/{nrser → lib/nrser}/functions/text/indent_spec.rb +0 -0
  62. data/spec/{nrser → lib/nrser}/functions/text/words_spec.rb +0 -0
  63. data/spec/{nrser → lib/nrser}/functions/tree/each_branch_spec.rb +0 -0
  64. data/spec/{nrser → lib/nrser}/functions/tree/leaves_spec.rb +0 -0
  65. data/spec/{nrser → lib/nrser}/functions/tree/map_branch_spec.rb +0 -0
  66. data/spec/{nrser → lib/nrser}/functions/tree/map_tree_spec.rb +0 -0
  67. data/spec/{nrser → lib/nrser}/functions/tree/transform_spec.rb +0 -0
  68. data/spec/{nrser → lib/nrser}/functions/tree/transformer_spec.rb +0 -0
  69. data/spec/{nrser → lib/nrser}/labs/globlin_spec.rb +0 -0
  70. data/spec/{nrser → lib/nrser}/labs/index_spec.rb +0 -0
  71. data/spec/{nrser → lib/nrser}/logger/dest_spec.rb +0 -0
  72. data/spec/{nrser → lib/nrser}/logger/die_spec.rb +0 -0
  73. data/spec/{nrser → lib/nrser}/logger/install_spec.rb +0 -0
  74. data/spec/{nrser → lib/nrser}/logger/level_int_spec.rb +0 -0
  75. data/spec/{nrser → lib/nrser}/logger/level_name_spec.rb +0 -0
  76. data/spec/{nrser → lib/nrser}/logger/level_sym_spec.rb +0 -0
  77. data/spec/{nrser → lib/nrser}/logger/send_log_spec.rb +0 -0
  78. data/spec/{nrser → lib/nrser}/logger/use_spec.rb +0 -0
  79. data/spec/lib/nrser/mean_streak/design_spec.rb +68 -0
  80. data/spec/lib/nrser/mean_streak/identity_instance_spec.rb +21 -0
  81. data/spec/{nrser → lib/nrser}/meta/class_attrs_spec.rb +0 -0
  82. data/spec/{nrser → lib/nrser}/meta/props/to_and_from_data_spec.rb +17 -11
  83. data/spec/{nrser → lib/nrser}/meta/props_spec.rb +0 -0
  84. data/spec/{nrser → lib/nrser}/op/message_spec.rb +0 -0
  85. data/spec/{nrser → lib/nrser}/refinements/array_spec.rb +0 -0
  86. data/spec/{nrser → lib/nrser}/refinements/erb_spec.rb +0 -0
  87. data/spec/{nrser → lib/nrser}/refinements/format_exception_spec.rb +0 -0
  88. data/spec/{nrser → lib/nrser}/refinements/hash_spec.rb +0 -0
  89. data/spec/{nrser → lib/nrser}/refinements/indent_spec.rb +0 -0
  90. data/spec/{nrser → lib/nrser}/refinements/object_spec.rb +0 -0
  91. data/spec/{nrser → lib/nrser}/refinements/pathname_spec.rb +0 -0
  92. data/spec/{nrser → lib/nrser}/refinements/set_spec.rb +0 -0
  93. data/spec/{nrser → lib/nrser}/refinements/truncate_spec.rb +0 -0
  94. data/spec/{nrser → lib/nrser}/types/array_spec.rb +0 -0
  95. data/spec/{nrser → lib/nrser}/types/attrs_spec.rb +0 -0
  96. data/spec/{nrser → lib/nrser}/types/combinators_spec.rb +0 -0
  97. data/spec/{nrser → lib/nrser}/types/is_spec.rb +0 -0
  98. data/spec/{nrser → lib/nrser}/types/pairs_spec.rb +0 -0
  99. data/spec/{nrser → lib/nrser}/types/paths_spec.rb +0 -0
  100. data/spec/{nrser → lib/nrser}/types/strings_spec.rb +0 -0
  101. data/spec/{nrser → lib/nrser}/types/symbols_spec.rb +1 -1
  102. data/spec/{nrser → lib/nrser}/types/tuples_spec.rb +0 -0
  103. data/spec/{nrser → lib/nrser}/types_spec.rb +0 -0
  104. data/spec/{nrser_spec.rb → lib/nrser_spec.rb} +0 -0
  105. metadata +148 -136
@@ -0,0 +1,71 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+ ##
4
+ # Functional methods to stylize a string through substitution
5
+ ##
6
+
7
+ module NRSER
8
+
9
+ # @!group String Functions
10
+ # ============================================================================
11
+
12
+ # Proxies to {NRSER::Char::AlphaNumericSub#sub} on
13
+ # {NRSER::Char::AlphaNumericSub.unicode_math_italic} to convert regular
14
+ # UTF-8/ASCII `a-zA-Z` characters to the "Unicode Math Italic" set.
15
+ #
16
+ # @param [String] string
17
+ # Input.
18
+ #
19
+ # @return [String]
20
+ # Output. Probably won't be `#ascii_only?`.
21
+ #
22
+ def self.u_italic string
23
+ NRSER::Char::AlphaNumericSub.unicode_math_italic.sub string
24
+ end
25
+
26
+
27
+ # Proxies to {NRSER::Char::AlphaNumericSub#sub} on
28
+ # {NRSER::Char::AlphaNumericSub.unicode_math_italic} to convert regular
29
+ # UTF-8/ASCII `a-zA-Z` characters to the "Unicode Math Italic" set.
30
+ #
31
+ # @param [String] string
32
+ # Input.
33
+ #
34
+ # @return [String]
35
+ # Output. Probably won't be `#ascii_only?`.
36
+ #
37
+ def self.u_bold string
38
+ NRSER::Char::AlphaNumericSub.unicode_math_bold.sub string
39
+ end
40
+
41
+
42
+ # Proxies to {NRSER::Char::AlphaNumericSub#sub} on
43
+ # {NRSER::Char::AlphaNumericSub.unicode_math_bold_italic} to convert regular
44
+ # UTF-8/ASCII `a-zA-Z` characters to the "Unicode Math Bold Italic" set.
45
+ #
46
+ # @param [String] string
47
+ # Input.
48
+ #
49
+ # @return [String]
50
+ # Output. Probably won't be `#ascii_only?`.
51
+ #
52
+ def self.u_bold_italic string
53
+ NRSER::Char::AlphaNumericSub.unicode_math_bold_italic.sub string
54
+ end
55
+
56
+
57
+ # Proxies to {NRSER::Char::AlphaNumericSub#sub} on
58
+ # {NRSER::Char::AlphaNumericSub.unicode_math_monospace} to convert regular
59
+ # UTF-8/ASCII `a-zA-Z` characters to the "Unicode Math Monospace" set.
60
+ #
61
+ # @param [String] string
62
+ # Input.
63
+ #
64
+ # @return [String]
65
+ # Output. Probably won't be `#ascii_only?`.
66
+ #
67
+ def self.u_mono string
68
+ NRSER::Char::AlphaNumericSub.unicode_math_monospace.sub string
69
+ end
70
+
71
+ end # module NRSER
@@ -12,6 +12,8 @@ require 'commonmarker'
12
12
 
13
13
  # Project / Package
14
14
  # -----------------------------------------------------------------------
15
+ require_relative './mean_streak/document'
16
+
15
17
 
16
18
  # Refinements
17
19
  # =======================================================================
@@ -61,14 +63,32 @@ class NRSER::MeanStreak
61
63
  # @return [CommonMarker::Node]
62
64
  # The `document` node.
63
65
  #
64
- def self.parse text, options = :DEFAULT, extensions = []
65
-
66
+ def self.parse source, options = :DEFAULT, extensions = []
67
+ default.parse source, cm_options: options, cm_extensions: extensions
68
+ end
69
+
70
+
71
+ # TODO document `type_renderers` attribute.
72
+ #
73
+ # @return [Hash<Symbol, Proc>]
74
+ #
75
+ attr_reader :type_renderers
76
+
77
+
78
+
79
+ def initialize &block
80
+ @type_renderers = {}
81
+ block.call( self ) if block
66
82
  end
67
83
 
68
84
 
69
85
  # Instance Methods
70
86
  # ============================================================================
71
87
 
88
+ def render_type type, &renderer
89
+ @type_renderers[type] = renderer
90
+ end
91
+
72
92
 
73
93
  # @todo Document parse method.
74
94
  #
@@ -86,10 +106,15 @@ class NRSER::MeanStreak
86
106
  end # #parse
87
107
 
88
108
 
109
+ def render doc_or_source
110
+ doc = if doc_or_source.is_a? NRSER::MeanStreak::Document
111
+ doc_or_source
112
+ else
113
+ parse doc_or_source
114
+ end
115
+
116
+ doc.render
117
+ end
118
+
119
+
89
120
  end # class NRSER::ShellDown
90
-
91
-
92
- # Post-Processing
93
- # =======================================================================
94
-
95
- require_relative './mean_streak/document'
@@ -1,30 +1,30 @@
1
+ # encoding: UTF-8
1
2
  # frozen_string_literal: true
2
3
 
3
4
  # Requirements
4
5
  # =======================================================================
5
6
 
6
- # Stdlib
7
- # -----------------------------------------------------------------------
8
-
9
7
  # Deps
10
8
  # -----------------------------------------------------------------------
11
-
12
- # Project / Package
13
- # -----------------------------------------------------------------------
9
+ require 'pastel'
14
10
 
15
11
 
16
12
  # Refinements
17
13
  # =======================================================================
18
14
 
15
+ using NRSER
16
+ using NRSER::Types
17
+
19
18
 
20
19
  # Declarations
21
20
  # =======================================================================
22
21
 
22
+ class NRSER::MeanStreak; end
23
+
23
24
 
24
25
  # Definitions
25
26
  # =======================================================================
26
27
 
27
-
28
28
  # @todo document NRSER::MeanStreak::Document class.
29
29
  class NRSER::MeanStreak::Document
30
30
 
@@ -49,7 +49,7 @@ class NRSER::MeanStreak::Document
49
49
  cm_extensions: []
50
50
  new mean_streak: mean_streak,
51
51
  source: source,
52
- doc: CommonMarker.render_doc( source, options, extensions )
52
+ doc: CommonMarker.render_doc( source, cm_options, cm_extensions )
53
53
  end # .parse
54
54
 
55
55
  singleton_class.send :alias_method, :from_string, :parse
@@ -99,53 +99,238 @@ class NRSER::MeanStreak::Document
99
99
 
100
100
  # Instance Methods
101
101
  # ======================================================================
102
-
102
+
103
+ def pastel
104
+ @pastel ||= Pastel.new
105
+ end
106
+
107
+
103
108
  # The lines in {#source} as a {Hamster::Vector} of frozen strings.
104
109
  #
105
110
  # @return [Hamster::Vector<String>]
106
111
  #
107
112
  def source_lines
108
- @source_lines = Hamster::Vector.new source.lines.map( &:freeze )
113
+ @source_lines ||= Hamster::List[*source.lines.map( &:freeze )]
109
114
  end
110
-
111
-
115
+
116
+
117
+ def source_byte_indexes node
118
+ pos = node.sourcepos
119
+
120
+ indexes = {
121
+ first_byte: {
122
+ line: pos[:start_line] - 1,
123
+ column: pos[:start_column] - 1,
124
+ },
125
+ last_byte: {
126
+ line: pos[:end_line] - 1,
127
+ column: pos[:end_column] - 1,
128
+ },
129
+ }
130
+
131
+ indexes.each do |key, byte_index_pos|
132
+ byte_index_pos[:index] = source_byte_index **byte_index_pos
133
+ end
134
+
135
+ indexes
136
+ end
137
+
138
+
139
+ def source_byte_index line:, column:
140
+ # source_lines[0...line].map( &:bytesize ).reduce( column, :+ )
141
+ byte_index = column
142
+ if line > 0
143
+ source_lines[0..(line - 1)].each { |_| byte_index += _.bytesize }
144
+ end
145
+ byte_index
146
+ end
147
+
148
+
149
+ def source_byteslice **kwds
150
+ t.and(
151
+ # All the values must be `nil` or non-negative integer
152
+ t.hash_(keys: t.sym, values: t.non_neg_int?),
153
+ # Exactly one of `start_on` and `start_after` must be `nil`
154
+ t.xor(t.shape(start_on: nil), t.shape(start_after: nil)),
155
+ # Exactly one of `end_on` and `end_before` must be `nil`
156
+ t.xor(t.shape(end_on: nil), t.shape(end_before: nil))
157
+ ).check kwds
158
+
159
+ # The first byte we're gonna slice is either the `start_on` keyword
160
+ # provided or the `start_after` bumped forward by 1 (which we can do
161
+ # because it must point to the last *byte* before the slice, *not the
162
+ # character*, so +1 gets us to the first slice byte)
163
+ start_on = kwds[:start_on] || (kwds[:start_after] + 1)
164
+
165
+ # In the same way, we can figure out the last byte after the slice
166
+ end_before = kwds[:end_before] || (kwds[:end_on] + 1)
167
+
168
+ # Sanity check
169
+ if start_on > end_before
170
+ # We done fucked up, which is not that unusual for me with this shit
171
+ raise "Shit... start_on: #{ start_on }, end_before: #{ end_before }"
172
+ end
173
+
174
+ # Take the slice... the `...` range seems kinda easier 'cause the resulting
175
+ # byte size is the difference `next_byte - end_before`
176
+ source.byteslice start_on...end_before
177
+ end
178
+
179
+
112
180
  # Get the substring of the source that a node came from (via its
113
181
  # `#sourcepos`).
114
182
  #
115
183
  # @return [String]
116
184
  #
117
185
  def source_for_node node
118
- pos = node.sourcepos
186
+ indexes = source_byte_indexes node
119
187
 
120
- if pos[:start_line] == pos[:end_line]
121
- source_lines[pos[:start_line] - 1][
122
- (pos[:start_column] - 1)...pos[:end_column]
123
- ]
124
- else
125
- lines = source_lines[(pos[:start_line] - 1)...pos[:end_line]]
126
-
127
- # Trim the start off the first line, unless the start column is 1
128
- unless pos[:start_column] == 1
129
- lines[0] = lines[0][(pos[:start_column] - 1)..-1]
188
+ # This one is *really* easy now!
189
+ source_byteslice(
190
+ # Start on the first byte
191
+ start_on: indexes[:first_byte][:index],
192
+ # End on the last
193
+ end_on: indexes[:last_byte][:index]
194
+ )
195
+ end
196
+
197
+
198
+ def source_between start_node, end_node
199
+ # Ok, all we do is take a byte slice based on their byte indexes
200
+ source_byteslice(
201
+ # The index of the start node's last type is the byte just *before*
202
+ # the slice starts
203
+ start_after: source_byte_indexes( start_node )[:last_byte][:index],
204
+ # The index of the end node's first byte is the byte just *after* the
205
+ # slice ends
206
+ end_before: source_byte_indexes( end_node )[:first_byte][:index]
207
+ )
208
+ end
209
+
210
+
211
+ def source_before_first_child node
212
+ slice = source_byteslice(
213
+ start_on: source_byte_indexes( node )[:first_byte][:index],
214
+ end_before: source_byte_indexes( node.first )[:first_byte][:index],
215
+ )
216
+
217
+ # See comments in {#render_children}
218
+ if mean_streak.type_renderers[:code] &&
219
+ node.first.type == :code &&
220
+ slice.start_with?( '`' )
221
+ slice = slice.sub /\A`+/, ''
222
+ end
223
+
224
+ slice
225
+ end
226
+
227
+
228
+ def source_after_last_child node
229
+ last_child = node.each.to_a.last
230
+
231
+ slice = source_byteslice(
232
+ start_after: source_byte_indexes( last_child )[:last_byte][:index],
233
+ end_on: source_byte_indexes( node )[:last_byte][:index]
234
+ )
235
+
236
+ # See comments in {#render_children}
237
+ if mean_streak.type_renderers[:code] &&
238
+ last_child.type == :code &&
239
+ slice.end_with?( '`' )
240
+ slice = slice.sub /`+\z/, ''
241
+ end
242
+
243
+ slice
244
+ end
245
+
246
+
247
+ def render_children node
248
+ prev = nil
249
+ parts = []
250
+ node.each do |child|
251
+ unless prev.nil?
252
+ between = source_between( prev, child )
253
+
254
+ # We may need to modify the source strings *surrounding* specific
255
+ # nodes...
256
+ #
257
+ # `:code` is an example thus far: it stores the code string in
258
+ # `#string_content` so - unlike `:emph` and `:strong` where the
259
+ # delimiters end up in the "before first child" and "after last child"
260
+ # *inside* the node's source slice - in `:code` they end up *outside*,
261
+ # in the source between it and the previous and next sibling nodes.
262
+ #
263
+ #
264
+ #
265
+ if mean_streak.type_renderers[:code]
266
+ # There is a renderer for the `:code` type, so assume that it will
267
+ # take are of any surrounding characters for `:code` strings and
268
+ # chomp off the starting and ending backticks
269
+ if prev.type == :code
270
+ # Previous node is `:code`, chomp off any leading backtick
271
+ # between = between[1..-1] if between.start_with?( '`' )
272
+ between = between.sub /\A`+/, ''
273
+ elsif child.type == :code
274
+ # Current node is `:code`, chomp off any leading backtick
275
+ between = between.sub /`+\z/, ''
276
+ end
277
+ end
278
+
279
+ parts << between
130
280
  end
131
281
 
132
- # Trim the end off the first line, unless the end column is the last
133
- # line's length
134
- unless pos[:end_column] == lines[-1].length
135
- lines[-1] = lines[-1][0...pos[:end_column]]
136
- end
282
+ parts << render_node( child )
137
283
 
138
- lines.join
284
+ prev = child
139
285
  end
286
+
287
+ parts.join
140
288
  end
141
-
142
-
143
- def render_node node, output = ''
289
+
290
+
291
+ def render_node_2 prev_node, source_before, node, source_after, next_node
144
292
 
145
293
  end
146
294
 
147
- end # class NRSER::MeanStreak::Document
148
-
149
295
 
150
- # Post-Processing
151
- # =======================================================================
296
+ def render_node node
297
+ if mean_streak.type_renderers[node.type]
298
+ mean_streak.type_renderers[node.type].call self, node
299
+ else
300
+ if node.first
301
+ # Has children
302
+ source_before_first_child( node ) +
303
+ render_children( node ) +
304
+ source_after_last_child( node )
305
+ else
306
+ # No children! Easy!
307
+ source_for_node node
308
+ end
309
+ end
310
+ end
311
+
312
+
313
+ def render
314
+ render_node doc
315
+ end
316
+
317
+
318
+ def find_by **attrs
319
+ doc.walk.find_all { |node|
320
+ attrs.all? { |name, value|
321
+ begin
322
+ value === node.send( name )
323
+ rescue
324
+ false
325
+ end
326
+ }
327
+ }
328
+ end
329
+
330
+
331
+ def find_type type
332
+ doc.walk.find_all { |node| node.type == type }
333
+ end
334
+
335
+
336
+ end # class NRSER::MeanStreak::Document