ruby-gumbo 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.mkd +28 -31
  4. data/Rakefile +60 -59
  5. data/ext/extconf.rb +17 -9
  6. data/ext/{gumbo.c → ruby_gumbo_ext.c} +29 -28
  7. data/lib/gumbo.rb +19 -0
  8. data/lib/gumbo/element.rb +52 -0
  9. data/lib/gumbo/{extra.rb → node.rb} +19 -22
  10. data/lib/gumbo/text.rb +29 -0
  11. data/vendor/gumbo-parser/src/attribute.c +44 -0
  12. data/vendor/gumbo-parser/src/attribute.h +37 -0
  13. data/vendor/gumbo-parser/src/char_ref.c +2561 -0
  14. data/vendor/gumbo-parser/src/char_ref.h +61 -0
  15. data/vendor/gumbo-parser/src/error.c +258 -0
  16. data/vendor/gumbo-parser/src/error.h +227 -0
  17. data/vendor/gumbo-parser/src/gumbo.h +807 -0
  18. data/vendor/gumbo-parser/src/insertion_mode.h +57 -0
  19. data/vendor/gumbo-parser/src/parser.c +3917 -0
  20. data/vendor/gumbo-parser/src/parser.h +57 -0
  21. data/vendor/gumbo-parser/src/string_buffer.c +106 -0
  22. data/vendor/gumbo-parser/src/string_buffer.h +81 -0
  23. data/vendor/gumbo-parser/src/string_piece.c +49 -0
  24. data/vendor/gumbo-parser/src/string_piece.h +39 -0
  25. data/vendor/gumbo-parser/src/tag.c +225 -0
  26. data/vendor/gumbo-parser/src/token_type.h +40 -0
  27. data/vendor/gumbo-parser/src/tokenizer.c +2980 -0
  28. data/vendor/gumbo-parser/src/tokenizer.h +123 -0
  29. data/vendor/gumbo-parser/src/tokenizer_states.h +103 -0
  30. data/vendor/gumbo-parser/src/utf8.c +275 -0
  31. data/vendor/gumbo-parser/src/utf8.h +127 -0
  32. data/vendor/gumbo-parser/src/util.c +58 -0
  33. data/vendor/gumbo-parser/src/util.h +62 -0
  34. data/vendor/gumbo-parser/src/vector.c +123 -0
  35. data/vendor/gumbo-parser/src/vector.h +69 -0
  36. metadata +40 -10
  37. data/ext/extconf.h +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f4e6f145bffad000b1a79454df8189d97e7f735
4
- data.tar.gz: 0bc3d6ba9be13e78e8cf204b8ae19c8346bb9943
3
+ metadata.gz: 9ab78fd0033219498d2f13464465c342930cdf5a
4
+ data.tar.gz: 949b7b24664379d5494889e81d44a4361d1dd839
5
5
  SHA512:
6
- metadata.gz: 10180229daad4eb0ccfa1207cc92e85cac055c58d1dca7e7e335258ab6bdbaf095c0acb8f1cb06a7b372fc7c37fcc00811c9f89853676be6935942e96fb54eb9
7
- data.tar.gz: 77e50622078d2275fd0c5c847610d1f2dd4b23871ad6b459c65d93085059c38102abb0ac75bf684ab042486c693939b090527803587350b9104fd83a47264e23
6
+ metadata.gz: 20fd4335420189d4bd4b7aa2247c43f681234ac6aca9f8d2e2292c72e398dc459a893b2c8bfbafca0a73f86c5ea73447b8dd48e3b4da6f79e36e9beaaeedc71d
7
+ data.tar.gz: a358f29bd205baf10a6437db066c92c3035d402b054c720b040cb8876b41809295c2e25a26b6b6e1a06f4c6094b768802f681a6701b8d90c8419704f342d62b4
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Nicolas Martyanoff
1
+ Copyright (c) 2014 the Ruby-Gumbo project authors
2
2
 
3
3
  Permission to use, copy, modify, and distribute this software for any
4
4
  purpose with or without fee is hereby granted, provided that the above
data/README.mkd CHANGED
@@ -1,48 +1,45 @@
1
1
  # ruby-gumbo
2
2
 
3
- ## Description
3
+ Ruby bindings for Google's [Gumbo][gumbo] HTML5
4
+ parser.
4
5
 
5
- `ruby-gumbo` is a ruby binding for the Gumbo HTML5 parser.
6
6
 
7
- ## Installation
7
+ ## Getting Started
8
8
 
9
- `ruby-gumbo` can be directly installed from http://rubygems.org:
9
+ Stick it in your `Gemfile`!
10
10
 
11
- gem install ruby-gumbo
12
-
13
- Or you can create the gem with `rake package`, then install it with `gem
14
- install` (the gem file is in the `pkg` directory).
11
+ ```ruby
12
+ gem 'ruby-gumbo', '~> 1.1'
13
+ ```
15
14
 
16
- ## Example
15
+ And then parse away:
17
16
 
18
17
  ```ruby
19
- require 'net/http'
20
-
21
- html = Net::HTTP.get URI.parse('http://example.org')
22
- Gumbo::parse(html) {|doc| doc.dump_tree}
18
+ require 'gumbo'
19
+ doc = Gumbo::parse(html)
23
20
  ```
24
21
 
25
- Result:
22
+ You'll probably want to peruse the [documentation][docs] to see how to navigate
23
+ a document and its nodes.
24
+
25
+
26
+ ## Developing
27
+
28
+ Grab the repository, and make sure to include submodules:
26
29
 
27
30
  ```
28
- <HTML>
29
- <HEAD>
30
- <TITLE>
31
- <META charset>
32
- <META http-equiv content>
33
- <META name content>
34
- <STYLE type>
35
- <BODY>
36
- <DIV>
37
- <H1>
38
- <P>
39
- <P>
40
- <A href>
31
+ git checkout https://github.com/nevir/ruby-gumbo --recursive
41
32
  ```
42
33
 
43
- You can find more examples in the `examples` directory.
34
+ And from there you should be able to `rake build` and `gem install pkg/*.gem`.
35
+
36
+
37
+ ## License
38
+
39
+ ruby-gumbo is licensed under the [ISC license](LICENSE), and packages the
40
+ [gumbo-parser library][gumbo] (APACHE v2.0).
44
41
 
45
- ## Contact
42
+ This is not a Google product and is not supported by Google in any way.
46
43
 
47
- If you have found a bug, have an idea or a question, email me at
48
- <khaelin@gmail.com>.
44
+ [gumbo]: https://github.com/google/gumbo-parser
45
+ [docs]: http://rubydoc.info/github/nevir/ruby-gumbo/master/frames
data/Rakefile CHANGED
@@ -1,79 +1,80 @@
1
-
2
1
  require 'rake/clean'
3
-
4
- require 'rdoc/task'
5
-
6
2
  require 'rubygems/package_task'
7
-
8
-
9
- PKG_NAME = "ruby-gumbo"
10
- PKG_VERSION = "1.0.2"
11
-
12
- EXT_CONF = "ext/extconf.rb"
13
- MAKEFILE = "ext/Makefile"
14
- MODULE = "ext/gumbo.so"
15
- SRC = Dir.glob("ext/*.c") << MAKEFILE
16
-
17
- CLEAN.include [MODULE, "ext/*.o"]
18
- CLOBBER.include ["ext/mkmf.log", "ext/extconf.h", MAKEFILE]
19
-
20
- # Build
21
- file MAKEFILE => EXT_CONF do |t|
22
- Dir::chdir(File::dirname(EXT_CONF)) do
23
- unless sh "ruby #{File::basename(EXT_CONF)}"
24
- $stderr.puts "extconf.rb failed"
25
- break
26
- end
3
+ require 'yard'
4
+
5
+ VERSION = '1.1.0'
6
+
7
+ BUILT_EXTENSION = "ext/gumbo_ext.#{RbConfig::CONFIG['DLEXT']}"
8
+ BUILT_FILES = FileList[
9
+ BUILT_EXTENSION,
10
+ ]
11
+ EXTENSION_SOURCE_FILES = FileList[
12
+ 'ext/extconf.rb',
13
+ 'ext/ruby_gumbo*.{h,c}',
14
+ ]
15
+ SOURCE_FILES = FileList[
16
+ 'Rakefile',
17
+ 'LICENSE',
18
+ 'README.mkd',
19
+ 'lib/**/*.rb',
20
+ *EXTENSION_SOURCE_FILES,
21
+ ]
22
+ VENDOR_FILES = FileList[
23
+ 'vendor/gumbo-parser/src/*',
24
+ ]
25
+ PACKAGED_FILES = FileList[
26
+ *BUILT_EXTENSION,
27
+ *SOURCE_FILES,
28
+ *VENDOR_FILES
29
+ ]
30
+
31
+ # Building
32
+
33
+ task :build => BUILT_EXTENSION
34
+
35
+ # Note that this will fail to pick up new files; you'll want to rake clean
36
+ # after adding/remove files. (The trade off is that versus rebuilding the
37
+ # Makefile each time an extension source file is touched).
38
+ file 'ext/Makefile' => ['ext/extconf.rb'] + VENDOR_FILES do
39
+ Dir.chdir 'ext' do
40
+ ruby 'extconf.rb'
27
41
  end
28
42
  end
29
43
 
30
- file MODULE => SRC do |t|
31
- Dir::chdir(File::dirname(EXT_CONF)) do
32
- unless sh "make"
33
- $stderr.puts "make failed"
34
- break
35
- end
44
+ file BUILT_EXTENSION => ['ext/Makefile'] + EXTENSION_SOURCE_FILES do
45
+ Dir.chdir 'ext' do
46
+ sh 'make'
36
47
  end
37
48
  end
38
49
 
39
- desc "Build the native library"
40
- task :build => MODULE
41
-
42
50
  # Documentation
43
- RDOC_FILES = FileList["ext/gumbo.c", "lib/gumbo/extra.rb"]
44
-
45
- Rake::RDocTask.new do |task|
46
- #task.main = "README.rdoc"
47
- task.rdoc_dir = "doc/api"
48
- task.rdoc_files.include(RDOC_FILES)
49
- end
50
51
 
51
- Rake::RDocTask.new(:ri) do |task|
52
- #task.main = "README.rdoc"
53
- task.rdoc_dir = "doc/ri"
54
- task.options << "--ri-system"
55
- task.rdoc_files.include(RDOC_FILES)
56
- end
52
+ YARD::Rake::YardocTask.new(:doc)
57
53
 
58
54
  # Packaging
59
- PKG_FILES = FileList["Rakefile", "LICENSE", "README.mkd",
60
- "lib/gumbo/*.rb",
61
- "ext/extconf.rb", "ext/*.[hc]"]
62
55
 
63
56
  SPEC = Gem::Specification.new do |spec|
64
- spec.name = PKG_NAME
65
- spec.version = PKG_VERSION
66
- spec.summary = "Ruby bindings for the gumbo html5 parser"
67
- spec.author = "Nicolas Martyanoff"
68
- spec.email = "khaelin@gmail.com"
69
- spec.license = "ISC"
57
+ spec.name = 'ruby-gumbo'
58
+ spec.version = VERSION
59
+ spec.summary = 'Ruby bindings for the gumbo html5 parser'
60
+ spec.authors = ['Nicolas Martyanoff', 'Ian MacLeod']
61
+ spec.email = ['khaelin@gmail.com', 'ian@nevir.net']
62
+ spec.license = 'ISC'
70
63
 
71
- spec.files = PKG_FILES
72
- spec.extensions = "ext/extconf.rb"
64
+ spec.files = SOURCE_FILES + VENDOR_FILES
65
+ spec.extensions = 'ext/extconf.rb'
73
66
 
74
- spec.required_ruby_version = ">= 1.9.3"
67
+ spec.required_ruby_version = '>= 1.9.3'
75
68
  end
76
69
 
77
70
  Gem::PackageTask.new(SPEC) do |pkg|
78
- pkg.need_tar = true
71
+ pkg.need_tar = true
72
+ pkg.need_zip = true
79
73
  end
74
+
75
+ # Cleaning
76
+
77
+ CLEAN.include('ext/**/*', '.yardoc')
78
+ CLEAN.exclude(*SOURCE_FILES, *BUILT_FILES)
79
+
80
+ CLOBBER.include('doc', *BUILT_FILES)
@@ -1,15 +1,23 @@
1
+ require 'mkmf'
1
2
 
2
- require "mkmf"
3
+ $CFLAGS << ' -std=c99'
3
4
 
4
- RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"] if ENV["CC"]
5
+ unless enable_config('packaged-library')
6
+ pkg_config('libgumbo')
7
+ end
5
8
 
6
- extension_name = "gumbo"
9
+ if enable_config('packaged-library') || !have_library('gumbo', 'gumbo_parse')
10
+ gumbo_lib_src = File.expand_path('../../vendor/gumbo-parser/src', __FILE__)
11
+ unless File.directory? gumbo_lib_src
12
+ abort "Couldn't find the packaged gumbo-parser library. " +
13
+ "Did you forget to git clone --recursive?"
14
+ end
15
+ require 'fileutils'
7
16
 
8
- unless pkg_config("libgumbo")
9
- $libs << " -lgumbo"
17
+ # mkmf doesn't appear to deal well with sources/objects in multiple
18
+ # directories, so we bring the gumbo source to it.
19
+ gumbo_sources = Dir[File.join(gumbo_lib_src, '*')]
20
+ FileUtils.cp(gumbo_sources, File.dirname(__FILE__))
10
21
  end
11
22
 
12
- $CFLAGS << " -std=c99"
13
-
14
- create_header
15
- create_makefile(extension_name)
23
+ create_makefile('gumbo_ext')
@@ -43,6 +43,7 @@ static VALUE r_gumbo_quirks_mode_to_symbol(GumboQuirksModeEnum mode);
43
43
  static VALUE r_gumbo_namespace_to_symbol(GumboNamespaceEnum ns);
44
44
  static VALUE r_gumbo_tag_to_symbol(GumboTag tag);
45
45
  static VALUE r_gumbo_node_to_value(GumboNode *node);
46
+ static VALUE r_gumbo_stringpiece_to_str(const GumboStringPiece* string);
46
47
 
47
48
  static VALUE r_gumbo_attribute_namespace_to_symbol(GumboAttributeNamespaceEnum ns);
48
49
  static VALUE r_gumbo_attribute_to_value(GumboAttribute *attribute);
@@ -55,7 +56,7 @@ static VALUE c_source_position;
55
56
 
56
57
 
57
58
  void
58
- Init_gumbo(void) {
59
+ Init_gumbo_ext(void) {
59
60
  m_gumbo = rb_define_module("Gumbo");
60
61
  rb_define_module_function(m_gumbo, "parse", r_gumbo_parse, 1);
61
62
 
@@ -76,6 +77,8 @@ Init_gumbo(void) {
76
77
  rb_define_attr(c_element, "tag", 1, 0);
77
78
  rb_define_attr(c_element, "original_tag", 1, 0);
78
79
  rb_define_attr(c_element, "original_tag_name", 1, 0);
80
+ rb_define_attr(c_element, "original_end_tag", 1, 0);
81
+ rb_define_attr(c_element, "original_end_tag_name", 1, 0);
79
82
  rb_define_attr(c_element, "tag_namespace", 1, 0);
80
83
  rb_define_attr(c_element, "attributes", 1, 0);
81
84
  rb_define_attr(c_element, "children", 1, 0);
@@ -89,20 +92,9 @@ Init_gumbo(void) {
89
92
  rb_define_attr(c_text, "original_text", 1, 0);
90
93
  rb_define_attr(c_text, "start_pos", 1, 0);
91
94
 
92
- c_cdata = rb_define_class_under(m_gumbo, "CData", c_node);
93
- rb_define_attr(c_cdata, "text", 1, 0);
94
- rb_define_attr(c_cdata, "original_text", 1, 0);
95
- rb_define_attr(c_cdata, "start_pos", 1, 0);
96
-
97
- c_comment = rb_define_class_under(m_gumbo, "Comment", c_node);
98
- rb_define_attr(c_comment, "text", 1, 0);
99
- rb_define_attr(c_comment, "original_text", 1, 0);
100
- rb_define_attr(c_comment, "start_pos", 1, 0);
101
-
102
- c_whitespace = rb_define_class_under(m_gumbo, "Whitespace", c_node);
103
- rb_define_attr(c_whitespace, "text", 1, 0);
104
- rb_define_attr(c_whitespace, "original_text", 1, 0);
105
- rb_define_attr(c_whitespace, "start_pos", 1, 0);
95
+ c_cdata = rb_define_class_under(m_gumbo, "CData", c_text);
96
+ c_comment = rb_define_class_under(m_gumbo, "Comment", c_text);
97
+ c_whitespace = rb_define_class_under(m_gumbo, "Whitespace", c_text);
106
98
 
107
99
  c_attribute = rb_define_class_under(m_gumbo, "Attribute", rb_cObject);
108
100
  rb_define_attr(c_attribute, "namespace", 1, 0);
@@ -240,7 +232,7 @@ r_tainted_str_new(const char *str, long len) {
240
232
 
241
233
  if (str) {
242
234
  val = rb_enc_str_new(str, len, rb_utf8_encoding());
243
- OBJ_TAINT(str);
235
+ OBJ_TAINT(val);
244
236
  } else {
245
237
  val = Qnil;
246
238
  }
@@ -258,6 +250,11 @@ r_tainted_cstr_new(const char *str) {
258
250
  return r_tainted_str_new(str, strlen(str));
259
251
  }
260
252
 
253
+ static VALUE
254
+ r_gumbo_stringpiece_to_str(const GumboStringPiece* string) {
255
+ return r_tainted_str_new(string->data, string->length);
256
+ }
257
+
261
258
  static VALUE
262
259
  r_gumbo_destroy_output(VALUE value) {
263
260
  GumboOutput *output;
@@ -431,12 +428,9 @@ r_gumbo_node_to_value(GumboNode *node) {
431
428
  rb_iv_set(r_node, "@tag",
432
429
  r_gumbo_tag_to_symbol(element->tag));
433
430
  rb_iv_set(r_node, "@original_tag",
434
- r_tainted_str_new(element->original_tag.data,
435
- element->original_tag.length));
436
- gumbo_tag_from_original_text(&element->original_tag);
437
- rb_iv_set(r_node, "@original_tag_name",
438
- r_tainted_str_new(element->original_tag.data,
439
- element->original_tag.length));
431
+ r_gumbo_stringpiece_to_str(&element->original_tag));
432
+ rb_iv_set(r_node, "@original_end_tag",
433
+ r_gumbo_stringpiece_to_str(&element->original_end_tag));
440
434
  rb_iv_set(r_node, "@tag_namespace",
441
435
  r_gumbo_namespace_to_symbol(element->tag_namespace));
442
436
  rb_iv_set(r_node, "@start_pos",
@@ -444,6 +438,16 @@ r_gumbo_node_to_value(GumboNode *node) {
444
438
  rb_iv_set(r_node, "@end_pos",
445
439
  r_gumbo_source_position_to_value(element->end_pos));
446
440
 
441
+ GumboStringPiece original_tag_name = element->original_tag;
442
+ gumbo_tag_from_original_text(&original_tag_name);
443
+ rb_iv_set(r_node, "@original_tag_name",
444
+ r_gumbo_stringpiece_to_str(&original_tag_name));
445
+
446
+ GumboStringPiece original_end_tag_name = element->original_end_tag;
447
+ gumbo_tag_from_original_text(&original_end_tag_name);
448
+ rb_iv_set(r_node, "@original_end_tag_name",
449
+ r_gumbo_stringpiece_to_str(&original_end_tag_name));
450
+
447
451
  r_attributes = rb_ary_new2(element->attributes.length);
448
452
  rb_iv_set(r_node, "@attributes", r_attributes);
449
453
 
@@ -466,8 +470,7 @@ r_gumbo_node_to_value(GumboNode *node) {
466
470
 
467
471
  rb_iv_set(r_node, "@text", r_tainted_cstr_new(text->text));
468
472
  rb_iv_set(r_node, "@original_text",
469
- r_tainted_str_new(text->original_text.data,
470
- text->original_text.length));
473
+ r_gumbo_stringpiece_to_str(&text->original_text));
471
474
  rb_iv_set(r_node, "@start_pos",
472
475
  r_gumbo_source_position_to_value(text->start_pos));
473
476
  }
@@ -520,12 +523,10 @@ r_gumbo_attribute_to_value(GumboAttribute *attribute) {
520
523
  r_gumbo_attribute_namespace_to_symbol(attribute->attr_namespace));
521
524
  rb_iv_set(r_attribute, "@name", r_tainted_cstr_new(attribute->name));
522
525
  rb_iv_set(r_attribute, "@original_name",
523
- r_tainted_str_new(attribute->original_name.data,
524
- attribute->original_name.length));
526
+ r_gumbo_stringpiece_to_str(&attribute->original_name));
525
527
  rb_iv_set(r_attribute, "@value", r_tainted_cstr_new(attribute->value));
526
528
  rb_iv_set(r_attribute, "@original_value",
527
- r_tainted_str_new(attribute->original_value.data,
528
- attribute->original_value.length));
529
+ r_gumbo_stringpiece_to_str(&attribute->original_value));
529
530
  rb_iv_set(r_attribute, "@name_start",
530
531
  r_gumbo_source_position_to_value(attribute->name_start));
531
532
  rb_iv_set(r_attribute, "@name_end",
@@ -0,0 +1,19 @@
1
+
2
+ # Copyright (c) 2013 Nicolas Martyanoff
3
+ #
4
+ # Permission to use, copy, modify, and distribute this software for any
5
+ # purpose with or without fee is hereby granted, provided that the above
6
+ # copyright notice and this permission notice appear in all copies.
7
+ #
8
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+
16
+ require 'gumbo_ext'
17
+ require 'gumbo/element'
18
+ require 'gumbo/node'
19
+ require 'gumbo/text'
@@ -0,0 +1,52 @@
1
+ # Copyright (c) 2013 Nicolas Martyanoff
2
+ #
3
+ # Permission to use, copy, modify, and distribute this software for any
4
+ # purpose with or without fee is hereby granted, provided that the above
5
+ # copyright notice and this permission notice appear in all copies.
6
+ #
7
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
+
15
+ require 'gumbo'
16
+
17
+ class Gumbo::Element
18
+ def to_s
19
+ if original_tag
20
+ open_tag = original_tag
21
+ end_tag = original_end_tag || ''
22
+ else
23
+ tag_name = original_tag_name || tag
24
+ open_tag = "<#{tag_name}>"
25
+ end_tag = "</#{tag_name}>"
26
+ end
27
+
28
+ open_tag + (children || []).map(&:to_s).join + end_tag
29
+ end
30
+ alias_method :inspect, :to_s
31
+
32
+ # The *byte* offset range where this element was extracted from, or nil if it
33
+ # was inserted algorithmically.
34
+ def offset_range
35
+ return nil unless original_tag
36
+ if original_end_tag
37
+ end_offset = end_pos.offset + original_end_tag.bytesize
38
+ else
39
+ end_offset = start_pos.offset + original_tag.bytesize
40
+ end
41
+
42
+ start_pos.offset...end_offset
43
+ end
44
+
45
+ # The *byte* offset range where the content inside this node exists, or nil if
46
+ # the node was inserted algorithmically, or has no content.
47
+ def content_range
48
+ return nil unless original_tag && original_end_tag
49
+
50
+ (start_pos.offset + original_tag.bytesize)...end_pos.offset
51
+ end
52
+ end