• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

satoren / y_ex / 0cfd1ca8381112c61b7fc9835296733fe19ea092

14 Mar 2025 12:56PM UTC coverage: 94.355% (-2.3%) from 96.632%
0cfd1ca8381112c61b7fc9835296733fe19ea092

push

github

web-flow
add as_prelim (#141)

* add as_prelim

8 of 21 new or added lines in 7 files covered. (38.1%)

468 of 496 relevant lines covered (94.35%)

21.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.23
/lib/shared_type/xml_element.ex
1
defmodule Yex.XmlElement do
2
  @moduledoc """
3
  A shared type that represents an XML node
4

5
  """
6

7
  alias Yex.Xml
8

9
  defstruct [
10
    :doc,
11
    :reference
12
  ]
13

14
  alias Yex.Doc
15
  require Yex.Doc
16

17
  @type t :: %__MODULE__{
18
          doc: Yex.Doc.t(),
19
          reference: reference()
20
        }
21

22
  @spec first_child(t) :: Yex.XmlElement.t() | Yex.XmlText.t() | nil
23
  def first_child(%__MODULE__{} = xml_element) do
24
    fetch(xml_element, 0)
25
    |> case do
14✔
26
      {:ok, node} -> node
12✔
27
      :error -> nil
2✔
28
    end
29
  end
30

31
  @spec children(t) :: Enumerable.t(Yex.XmlElement.t() | Yex.XmlText.t())
32
  def children(%__MODULE__{doc: doc} = xml_element) do
33
    Doc.run_in_worker_process(doc,
7✔
34
      do:
35
        Stream.unfold(first_child(xml_element), fn
7✔
36
          nil -> nil
6✔
37
          xml -> {xml, Xml.next_sibling(xml)}
21✔
38
        end)
39
    )
40
  end
41

42
  @spec length(t) :: integer()
43
  def length(%__MODULE__{doc: doc} = xml_element) do
44
    Doc.run_in_worker_process(doc,
39✔
45
      do: Yex.Nif.xml_element_length(xml_element, cur_txn(xml_element))
39✔
46
    )
47
  end
48

49
  @spec insert(t, integer(), Yex.XmlElementPrelim.t() | Yex.XmlTextPrelim.t()) :: :ok | :error
50
  def insert(%__MODULE__{doc: doc} = xml_element, index, content) do
51
    Doc.run_in_worker_process(doc,
39✔
52
      do: Yex.Nif.xml_element_insert(xml_element, cur_txn(xml_element), index, content)
39✔
53
    )
54
  end
55

56
  @spec insert_after(
57
          t,
58
          Yex.XmlElement.t() | Yex.XmlText.t(),
59
          Yex.XmlElementPrelim.t() | Yex.XmlTextPrelim.t()
60
        ) :: :ok | :error
61
  def insert_after(%__MODULE__{doc: doc} = xml_element, ref, content) do
62
    Doc.run_in_worker_process doc do
2✔
63
      index = children(xml_element) |> Enum.find_index(&(&1 == ref))
2✔
64

65
      if index == nil do
2✔
66
        insert(xml_element, 0, content)
1✔
67
      else
68
        insert(xml_element, index + 1, content)
1✔
69
      end
70
    end
71
  end
72

73
  @spec delete(t, integer(), integer()) :: :ok | :error
74
  def delete(%__MODULE__{doc: doc} = xml_element, index, length) do
75
    Doc.run_in_worker_process(doc,
3✔
76
      do: Yex.Nif.xml_element_delete_range(xml_element, cur_txn(xml_element), index, length)
3✔
77
    )
78
  end
79

80
  @spec push(t, Yex.XmlElementPrelim.t() | Yex.XmlTextPrelim.t()) :: :ok | :error
81
  def push(%__MODULE__{doc: doc} = xml_element, content) do
82
    Doc.run_in_worker_process(doc,
30✔
83
      do: insert(xml_element, __MODULE__.length(xml_element), content)
30✔
84
    )
85
  end
86

87
  @spec unshift(t, Yex.XmlElementPrelim.t() | Yex.XmlTextPrelim.t()) :: :ok | :error
88
  def unshift(%__MODULE__{} = xml_element, content) do
89
    insert(xml_element, 0, content)
1✔
90
  end
91

92
  @deprecated "Rename to `fetch/2`"
93
  @spec get(t, integer()) :: {:ok, Yex.XmlElement.t() | Yex.XmlText.t()} | :error
94
  def get(%__MODULE__{} = xml_element, index) do
95
    fetch(xml_element, index)
1✔
96
  end
97

98
  @spec fetch(t, integer()) :: {:ok, Yex.XmlElement.t() | Yex.XmlText.t()} | :error
99
  def fetch(%__MODULE__{doc: doc} = xml_element, index) do
100
    Doc.run_in_worker_process(doc,
30✔
101
      do: Yex.Nif.xml_element_get(xml_element, cur_txn(xml_element), index)
30✔
102
    )
103
  end
104

105
  @spec fetch(t, integer()) :: Yex.XmlElement.t() | Yex.XmlText.t()
106
  def fetch!(%__MODULE__{} = map, index) do
107
    case fetch(map, index) do
11✔
108
      {:ok, value} -> value
10✔
109
      :error -> raise ArgumentError, "Index out of bounds"
1✔
110
    end
111
  end
112

113
  @spec insert_attribute(t, binary(), binary()) :: :ok | :error
114
  def insert_attribute(%__MODULE__{doc: doc} = xml_element, key, value) do
115
    Doc.run_in_worker_process(doc,
10✔
116
      do: Yex.Nif.xml_element_insert_attribute(xml_element, cur_txn(xml_element), key, value)
10✔
117
    )
118
  end
119

120
  @spec remove_attribute(t, binary()) :: :ok | :error
121
  def remove_attribute(%__MODULE__{doc: doc} = xml_element, key) do
122
    Doc.run_in_worker_process(doc,
2✔
123
      do: Yex.Nif.xml_element_remove_attribute(xml_element, cur_txn(xml_element), key)
2✔
124
    )
125
  end
126

127
  @doc """
128
  Get the tag of the xml element.
129
  """
130
  @spec get_tag(t) :: binary() | nil
131
  def get_tag(%__MODULE__{doc: doc} = xml_element) do
132
    Doc.run_in_worker_process(doc,
4✔
133
      do: Yex.Nif.xml_element_get_tag(xml_element, cur_txn(xml_element))
4✔
134
    )
135
  end
136

137
  @spec get_attribute(t, binary()) :: binary() | nil
138
  def get_attribute(%__MODULE__{doc: doc} = xml_element, key) do
139
    Doc.run_in_worker_process(doc,
5✔
140
      do: Yex.Nif.xml_element_get_attribute(xml_element, cur_txn(xml_element), key)
5✔
141
    )
142
  end
143

144
  @spec get_attributes(t) :: map()
145
  def get_attributes(%__MODULE__{doc: doc} = xml_element) do
146
    Doc.run_in_worker_process(doc,
3✔
147
      do: Yex.Nif.xml_element_get_attributes(xml_element, cur_txn(xml_element))
3✔
148
    )
149
  end
150

151
  @doc """
152
  The next sibling of this type. Is null if this is the last child of its parent.
153
  """
154
  @spec next_sibling(t) :: Yex.XmlElement.t() | Yex.XmlText.t() | nil
155
  def next_sibling(%__MODULE__{doc: doc} = xml_element) do
156
    Doc.run_in_worker_process(doc,
14✔
157
      do: Yex.Nif.xml_element_next_sibling(xml_element, cur_txn(xml_element))
14✔
158
    )
159
  end
160

161
  @doc """
162
  The previous sibling of this type. Is null if this is the first child of its parent.
163
  """
164
  @spec prev_sibling(t) :: Yex.XmlElement.t() | Yex.XmlText.t() | nil
165
  def prev_sibling(%__MODULE__{doc: doc} = xml_element) do
166
    Doc.run_in_worker_process(doc,
5✔
167
      do: Yex.Nif.xml_element_prev_sibling(xml_element, cur_txn(xml_element))
5✔
168
    )
169
  end
170

171
  @doc """
172
  The parent that holds this type. Is null if this xml is a top-level XML type.
173
  """
174
  @spec parent(t) :: Yex.XmlElement.t() | Yex.XmlFragment.t() | nil
175
  def parent(%__MODULE__{doc: doc} = xml_element) do
176
    Doc.run_in_worker_process(doc,
3✔
177
      do: Yex.Nif.xml_element_parent(xml_element, cur_txn(xml_element))
3✔
178
    )
179
  end
180

181
  @spec to_string(t) :: binary()
182
  def to_string(%__MODULE__{doc: doc} = xml_element) do
183
    Doc.run_in_worker_process(doc,
8✔
184
      do: Yex.Nif.xml_element_to_string(xml_element, cur_txn(xml_element))
8✔
185
    )
186
  end
187

188
  defp cur_txn(%{doc: %Yex.Doc{reference: doc_ref}}) do
189
    Process.get(doc_ref, nil)
165✔
190
  end
191

192
  @spec as_prelim(t) :: Yex.XmlElementPrelim.t()
193
  def as_prelim(%__MODULE__{} = xml_element) do
NEW
194
    children =
×
195
      Enum.map(0..(__MODULE__.length(xml_element) - 1), fn i ->
NEW
196
        {:ok, child} = fetch(xml_element, i)
×
NEW
197
        Yex.Output.as_prelim(child)
×
198
      end)
199

NEW
200
    Yex.XmlElementPrelim.new(
×
201
      get_tag(xml_element),
202
      children,
203
      get_attributes(xml_element)
204
    )
205
  end
206

207
  defimpl Yex.Output do
208
    def as_prelim(xml_element) do
NEW
209
      Yex.XmlElement.as_prelim(xml_element)
×
210
    end
211
  end
212

213
  defimpl Yex.Xml do
214
    defdelegate next_sibling(xml), to: Yex.XmlElement
13✔
215
    defdelegate prev_sibling(xml), to: Yex.XmlElement
4✔
216
    defdelegate parent(xml), to: Yex.XmlElement
1✔
217
    defdelegate to_string(xml), to: Yex.XmlElement
1✔
218
  end
219
end
220

221
defmodule Yex.XmlElementPrelim do
222
  @moduledoc """
223
  A preliminary xml element. It can be used to early initialize the contents of a XmlElement.
224

225
  ## Examples
226
      iex> doc = Yex.Doc.new()
227
      iex> xml = Yex.Doc.get_xml_fragment(doc, "xml")
228
      iex> Yex.XmlFragment.insert(xml, 0,  Yex.XmlElementPrelim.empty("div"))
229
      iex> Yex.XmlFragment.to_string(xml)
230
      "<div></div>"
231

232
  """
233
  defstruct [:tag, :attributes, :children]
234

235
  @type t :: %__MODULE__{
236
          tag: String.t(),
237
          attributes: %{String.t() => String.t()},
238
          children: [Yex.XmlElementPrelim.t() | Yex.XmlTextPrelim.t()]
239
        }
240

241
  def new(tag, children, attributes \\ %{}) do
242
    %__MODULE__{
13✔
243
      tag: tag,
244
      attributes: attributes,
245
      children: Enum.to_list(children)
246
    }
247
  end
248

249
  def empty(tag) do
250
    %__MODULE__{
73✔
251
      tag: tag,
252
      attributes: %{},
253
      children: []
254
    }
255
  end
256
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc