dommy 0.5.0

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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +213 -0
  3. data/lib/dommy/attr.rb +200 -0
  4. data/lib/dommy/blob.rb +182 -0
  5. data/lib/dommy/bridge.rb +141 -0
  6. data/lib/dommy/css.rb +283 -0
  7. data/lib/dommy/custom_elements.rb +125 -0
  8. data/lib/dommy/data_transfer.rb +98 -0
  9. data/lib/dommy/document.rb +674 -0
  10. data/lib/dommy/dom_exception.rb +258 -0
  11. data/lib/dommy/dom_parser.rb +88 -0
  12. data/lib/dommy/element.rb +1975 -0
  13. data/lib/dommy/event.rb +589 -0
  14. data/lib/dommy/fetch.rb +241 -0
  15. data/lib/dommy/form_data.rb +208 -0
  16. data/lib/dommy/html_collection.rb +207 -0
  17. data/lib/dommy/html_elements.rb +4455 -0
  18. data/lib/dommy/internal/cookie_jar.rb +27 -0
  19. data/lib/dommy/internal/dom_matching.rb +141 -0
  20. data/lib/dommy/internal/mutation_coordinator.rb +172 -0
  21. data/lib/dommy/internal/node_traversal.rb +36 -0
  22. data/lib/dommy/internal/node_wrapper_cache.rb +179 -0
  23. data/lib/dommy/internal/observer_manager.rb +31 -0
  24. data/lib/dommy/internal/observer_matcher.rb +31 -0
  25. data/lib/dommy/internal/scope_resolution.rb +27 -0
  26. data/lib/dommy/internal/shadow_root_registry.rb +35 -0
  27. data/lib/dommy/internal/template_content_registry.rb +97 -0
  28. data/lib/dommy/minitest/assertions.rb +105 -0
  29. data/lib/dommy/minitest.rb +17 -0
  30. data/lib/dommy/navigator.rb +271 -0
  31. data/lib/dommy/node.rb +218 -0
  32. data/lib/dommy/observer.rb +199 -0
  33. data/lib/dommy/parser.rb +29 -0
  34. data/lib/dommy/promise.rb +199 -0
  35. data/lib/dommy/router.rb +275 -0
  36. data/lib/dommy/rspec/capy_style_matchers.rb +356 -0
  37. data/lib/dommy/rspec/matchers.rb +230 -0
  38. data/lib/dommy/rspec.rb +18 -0
  39. data/lib/dommy/scheduler.rb +135 -0
  40. data/lib/dommy/shadow_root.rb +255 -0
  41. data/lib/dommy/storage.rb +112 -0
  42. data/lib/dommy/test_helpers.rb +78 -0
  43. data/lib/dommy/tree_walker.rb +425 -0
  44. data/lib/dommy/url.rb +479 -0
  45. data/lib/dommy/version.rb +5 -0
  46. data/lib/dommy/world.rb +209 -0
  47. data/lib/dommy.rb +119 -0
  48. metadata +110 -0
data/lib/dommy.rb ADDED
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "nokogiri"
4
+ require "set"
5
+
6
+ require_relative "dommy/version"
7
+ require_relative "dommy/dom_exception"
8
+ require_relative "dommy/node"
9
+ require_relative "dommy/html_collection"
10
+ require_relative "dommy/event"
11
+ require_relative "dommy/scheduler"
12
+ require_relative "dommy/observer"
13
+ require_relative "dommy/promise"
14
+ require_relative "dommy/blob"
15
+ require_relative "dommy/data_transfer"
16
+ require_relative "dommy/bridge"
17
+ require_relative "dommy/storage"
18
+ require_relative "dommy/fetch"
19
+ require_relative "dommy/router"
20
+ require_relative "dommy/navigator"
21
+ require_relative "dommy/parser"
22
+ require_relative "dommy/attr"
23
+ require_relative "dommy/world"
24
+ require_relative "dommy/document"
25
+ require_relative "dommy/element"
26
+ require_relative "dommy/html_elements"
27
+ require_relative "dommy/shadow_root"
28
+ require_relative "dommy/custom_elements"
29
+ require_relative "dommy/tree_walker"
30
+ require_relative "dommy/url"
31
+ require_relative "dommy/form_data"
32
+ require_relative "dommy/dom_parser"
33
+ require_relative "dommy/css"
34
+
35
+ module Dommy
36
+ # Parse an HTML string and return a fresh `Window`.
37
+ #
38
+ # When the input starts with `<!doctype` or `<html>`, it is parsed as
39
+ # a full HTML document (preserving <head>, <title>, etc.). Otherwise
40
+ # the input is treated as a body fragment and inserted into a fresh
41
+ # document's <body>.
42
+ #
43
+ # The Window has no host (standalone CRuby usage); embedders that need
44
+ # bridge callbacks (e.g. a wasm host) pass a host instead.
45
+ def self.parse(html)
46
+ s = html.to_s
47
+ if s.match?(/\A\s*(<!doctype|<html\b)/i)
48
+ Window.new(nil, nokogiri_doc: Nokogiri::HTML5(s))
49
+ else
50
+ window = Window.new
51
+ window.document.body.inner_html = s
52
+ window
53
+ end
54
+ end
55
+
56
+ # Build a fresh, empty Window (no host). Equivalent to opening a
57
+ # blank document.
58
+ def self.new_window
59
+ Window.new
60
+ end
61
+
62
+ # `structuredClone(value)` — deep clone for plain Ruby values and
63
+ # DOM nodes (via `cloneNode(true)`). Mirrors the JS structured-clone
64
+ # algorithm for the subset we support:
65
+ #
66
+ # - primitives (String / Numeric / Boolean / nil) → copied
67
+ # - Array / Hash / Set → deep-cloned
68
+ # - DOM nodes (anything responding to `clone_node`) → deep-cloned
69
+ # - cyclic structures → preserved
70
+ # - Proc / Method / Class / Module / IO → DataCloneError
71
+ #
72
+ # Symbols are passed through unchanged (Ruby has no `Symbol` clone
73
+ # concept; JS treats Symbols as DataCloneError, but Ruby code uses
74
+ # them as hash keys so this is the pragmatic choice).
75
+ def self.structured_clone(value, memo = {})
76
+ return memo[value.object_id] if memo.key?(value.object_id)
77
+
78
+ case value
79
+ when nil, true, false, Numeric, Symbol
80
+ value
81
+ when String
82
+ value.dup
83
+ when Array
84
+ arr = []
85
+ memo[value.object_id] = arr
86
+ value.each { |v| arr << structured_clone(v, memo) }
87
+ arr
88
+ when Hash
89
+ h = {}
90
+ memo[value.object_id] = h
91
+ value.each { |k, v| h[structured_clone(k, memo)] = structured_clone(v, memo) }
92
+ h
93
+ when Set
94
+ s = Set.new
95
+ memo[value.object_id] = s
96
+ value.each { |v| s << structured_clone(v, memo) }
97
+ s
98
+ when Time
99
+ value.dup
100
+ when Regexp
101
+ value.dup
102
+ when Proc, Method, UnboundMethod, IO, Class, Module
103
+ raise DOMException::DataCloneError, "#{value.class} cannot be cloned"
104
+ else
105
+ if value.respond_to?(:clone_node)
106
+ value.clone_node(true)
107
+ else
108
+ # Fallback: rely on the object's own `dup` (which handles
109
+ # custom classes the user might pass through).
110
+ value.dup
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ # JS-style global alias for symmetry with `window.structuredClone(...)`.
117
+ def Dommy.structuredClone(value)
118
+ structured_clone(value)
119
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dommy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - takahashim
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2026-05-21 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: nokogiri
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.15'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.15'
26
+ description: |
27
+ A pure-Ruby DOM polyfill on top of Nokogiri::HTML5, a Ruby-side
28
+ analogue to JavaScript DOM libraries like happy-dom and jsdom.
29
+ It exposes browser-like DOM semantics — events, MutationObserver,
30
+ Custom Elements, Shadow DOM, the File API (Blob / File / FormData /
31
+ DataTransfer), URL, Promise, timers, and Storage — without spinning
32
+ up a real browser.
33
+
34
+ Aimed at testing Ruby code that emits or consumes HTML. Includes
35
+ drop-in RSpec matchers and Minitest assertions.
36
+ email:
37
+ - takahashimm@gmail.com
38
+ executables: []
39
+ extensions: []
40
+ extra_rdoc_files: []
41
+ files:
42
+ - README.md
43
+ - lib/dommy.rb
44
+ - lib/dommy/attr.rb
45
+ - lib/dommy/blob.rb
46
+ - lib/dommy/bridge.rb
47
+ - lib/dommy/css.rb
48
+ - lib/dommy/custom_elements.rb
49
+ - lib/dommy/data_transfer.rb
50
+ - lib/dommy/document.rb
51
+ - lib/dommy/dom_exception.rb
52
+ - lib/dommy/dom_parser.rb
53
+ - lib/dommy/element.rb
54
+ - lib/dommy/event.rb
55
+ - lib/dommy/fetch.rb
56
+ - lib/dommy/form_data.rb
57
+ - lib/dommy/html_collection.rb
58
+ - lib/dommy/html_elements.rb
59
+ - lib/dommy/internal/cookie_jar.rb
60
+ - lib/dommy/internal/dom_matching.rb
61
+ - lib/dommy/internal/mutation_coordinator.rb
62
+ - lib/dommy/internal/node_traversal.rb
63
+ - lib/dommy/internal/node_wrapper_cache.rb
64
+ - lib/dommy/internal/observer_manager.rb
65
+ - lib/dommy/internal/observer_matcher.rb
66
+ - lib/dommy/internal/scope_resolution.rb
67
+ - lib/dommy/internal/shadow_root_registry.rb
68
+ - lib/dommy/internal/template_content_registry.rb
69
+ - lib/dommy/minitest.rb
70
+ - lib/dommy/minitest/assertions.rb
71
+ - lib/dommy/navigator.rb
72
+ - lib/dommy/node.rb
73
+ - lib/dommy/observer.rb
74
+ - lib/dommy/parser.rb
75
+ - lib/dommy/promise.rb
76
+ - lib/dommy/router.rb
77
+ - lib/dommy/rspec.rb
78
+ - lib/dommy/rspec/capy_style_matchers.rb
79
+ - lib/dommy/rspec/matchers.rb
80
+ - lib/dommy/scheduler.rb
81
+ - lib/dommy/shadow_root.rb
82
+ - lib/dommy/storage.rb
83
+ - lib/dommy/test_helpers.rb
84
+ - lib/dommy/tree_walker.rb
85
+ - lib/dommy/url.rb
86
+ - lib/dommy/version.rb
87
+ - lib/dommy/world.rb
88
+ homepage: https://github.com/takahashim/dommy
89
+ licenses:
90
+ - MIT
91
+ metadata:
92
+ homepage_uri: https://github.com/takahashim/dommy
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '3.0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubygems_version: 3.6.2
108
+ specification_version: 4
109
+ summary: happy-dom-style DOM polyfill in pure Ruby
110
+ test_files: []