objective_elements 1.1.1 → 2.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e2d1f8b25c51909941b93851d03b35750d6f565a96c79e15c4fc7b335c8569b
4
- data.tar.gz: cfc29825193a34c5d5fe1c6aa279cd2d5767181639afa1080eba7faad0081091
3
+ metadata.gz: a8c175b8c8ee5cb41bcdc79101e658706bc82c930ba3bbb64675cf805375297d
4
+ data.tar.gz: 234cba6e82854442b3780df1cde7d0b394d5acca7b649c695d8e697379eb213f
5
5
  SHA512:
6
- metadata.gz: 35c68f9a39dbe6da0ab4ff7681bff27ec230a1633c0d991c7015bd359225cd92b7d6b9ed02a1e5563a9a2675953e715ec55b851c62c59e4a61185ab7188f459a
7
- data.tar.gz: a6fb2881ad600bde01391a56359a3a35459d957e561cc9b5c0cdd20bfe66b1028c6c636d7711bff67b89a6321a39230b6ed9ce18578898aa26d5449f3c55fbcb
6
+ metadata.gz: be1b67a8c7df385802f168ed9684453d378343c56180da10859be98d545e3ac934f56092f27573992c18cea56e7fd2a91fc2d7fc715dc486609d07186f15f7d9
7
+ data.tar.gz: b2220420f60c50ea537ac4bfeb94e6287452c38b820f7c9d59c16458ef00d2dc7b653e5802868cc330d4ad4742bceb2d570b55f1c237313cdece0cca33acc234
@@ -0,0 +1,44 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+
8
+ jobs:
9
+ spec:
10
+ name: rspec (ruby ${{ matrix.ruby }})
11
+ runs-on: ${{ matrix.runs-on || 'ubuntu-latest' }}
12
+ continue-on-error: ${{ matrix.experimental || false }}
13
+
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ ruby: ["3.2", "3.3", "3.4", "4.0"]
18
+ include:
19
+ # setup-ruby has no 3.0 build for images newer than 22.04.
20
+ - ruby: "3.0"
21
+ runs-on: ubuntu-22.04
22
+ - ruby: ruby-head
23
+ experimental: true
24
+
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ - uses: ruby/setup-ruby@v1
28
+ with:
29
+ ruby-version: ${{ matrix.ruby }}
30
+ bundler-cache: true
31
+ - run: bundle exec rspec
32
+
33
+ rubocop:
34
+ name: rubocop
35
+ runs-on: ubuntu-latest
36
+
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+ - uses: ruby/setup-ruby@v1
40
+ with:
41
+ # Matches the version mise.toml pins, so local and CI lint agree.
42
+ ruby-version: "3.4"
43
+ bundler-cache: true
44
+ - run: bundle exec rubocop
@@ -0,0 +1,28 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+ # Publishes whatever version.rb says on the selected branch. Needed for
7
+ # v2.0.0, whose tag predates this workflow. `rake release` skips tagging when
8
+ # the tag already exists, so this is safe to re-run.
9
+ workflow_dispatch:
10
+
11
+ jobs:
12
+ release:
13
+ name: push to rubygems
14
+ runs-on: ubuntu-latest
15
+
16
+ permissions:
17
+ contents: read
18
+ # Required for the OIDC token rubygems.org trades for a scoped API key.
19
+ id-token: write
20
+
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - uses: ruby/setup-ruby@v1
24
+ with:
25
+ # Matches the version mise.toml pins.
26
+ ruby-version: "3.4"
27
+ bundler-cache: true
28
+ - uses: rubygems/release-gem@v1
data/.gitignore CHANGED
@@ -6,3 +6,4 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ Gemfile.lock
data/.rubocop.yml ADDED
@@ -0,0 +1,3 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0
3
+ NewCops: enable
data/AGENTS.md ADDED
@@ -0,0 +1,35 @@
1
+ # AGENTS.md
2
+
3
+ This project is a small ruby gem for building HTML tags.
4
+
5
+ ## Commits
6
+
7
+ - All AI assisted commits should have a trailer: `Assisted-by: <model>`
8
+ - [Scoped commits](https://scopedcommits.com/), not conventional commits. Short version:
9
+
10
+ ```
11
+ <scope>: <description>
12
+
13
+ [optional body]
14
+
15
+ [optional trailer(s)]
16
+ ```
17
+
18
+ - <scope> — the subsystem, area, or module that the commit touches
19
+ - <description> — a short description of the changes made
20
+ - [optional body] — detailed information about the changes
21
+ - [optional trailer(s)] — additional metadata about the commit
22
+
23
+ ## Agent skills
24
+
25
+ ### Issue tracker
26
+
27
+ Issues live in GitHub Issues for `rbuchberger/objective_elements`, managed via the `gh` CLI. See `docs/agents/issue-tracker.md`.
28
+
29
+ ### Triage labels
30
+
31
+ The five canonical triage roles, each using its default label string. See `docs/agents/triage-labels.md`.
32
+
33
+ ### Domain docs
34
+
35
+ Single-context: `CONTEXT.md` and `docs/adr/` at the repo root. See `docs/agents/domain.md`.
data/CHANGELOG.md ADDED
@@ -0,0 +1,75 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [2.0.0] - 2026-08-12
9
+
10
+ ### Changed
11
+
12
+ - **Breaking:** `required_ruby_version` is now `>= 3.0`, with no upper bound.
13
+ See [ADR 0001](docs/adr/0001-ruby-version-support-policy.md) for the support
14
+ policy and the April 2027 expiry of the 3.0 floor.
15
+ - All source files now declare `# frozen_string_literal: true`.
16
+ - `ShelfTag#initialize` calls `super`, so a ShelfTag now has a `nil` element and
17
+ an empty `HTMLAttributes` rather than no attributes at all.
18
+
19
+ ### Fixed
20
+
21
+ - `HTMLAttributes#to_s` no longer mutates the attribute hash. Previously an
22
+ empty attribute gained an empty string on every render, so repeated calls
23
+ accumulated trailing spaces.
24
+ - `HTMLAttributes#to_s`, `SingleTag#opening_tag`, and `DoubleTag#to_a` built
25
+ their output by mutating string literals, which raised `FrozenError` under
26
+ frozen string literals.
27
+ - `bin/console` required the gem's pre-rename name and could not start.
28
+
29
+ ### Added
30
+
31
+ - GitHub Actions CI: rspec on Ruby 3.0, 3.2, 3.3, 3.4, and 4.0, plus a
32
+ `ruby-head` leg that is allowed to fail, and rubocop on 3.4.
33
+ - Gemspec metadata URIs, and `rubygems_mfa_required`.
34
+ - `mise.toml`, pinning Ruby 3.4 for development.
35
+ - This changelog. Earlier entries are transcribed from the README's old
36
+ "Changes" section.
37
+
38
+ ### Removed
39
+
40
+ - `bundler`, `pry`, and `solargraph` as declared development dependencies, and
41
+ `.solargraph.yml`. Install those locally instead.
42
+ - `Gemfile.lock`, which is now gitignored — one lockfile can't serve a Ruby
43
+ 3.0 through 4.0 matrix.
44
+
45
+ ## [1.1.2] - 2020-01-16
46
+
47
+ ### Changed
48
+
49
+ - Gemspec and dependency housekeeping. No functional changes.
50
+
51
+ ## [1.1.1] - 2019-11-14
52
+
53
+ ### Fixed
54
+
55
+ - Duplicate attribute keys passed at the same time no longer overwrite each
56
+ other's values.
57
+
58
+ ## [1.1.0] - 2019-02-08
59
+
60
+ ### Added
61
+
62
+ - `ShelfTag`, for creating siblings without a parent element.
63
+
64
+ ## [1.0.0] - 2018-10-23
65
+
66
+ ### Changed
67
+
68
+ - **Breaking:** attributes syntax changed significantly. `.add_attributes`
69
+ became `.attributes <<`; see the README's usage section.
70
+
71
+ [unreleased]: https://github.com/rbuchberger/objective_elements/compare/v1.1.2...HEAD
72
+ [1.1.2]: https://github.com/rbuchberger/objective_elements/compare/v1.1.1...v1.1.2
73
+ [1.1.1]: https://github.com/rbuchberger/objective_elements/compare/v1.1.0...v1.1.1
74
+ [1.1.0]: https://github.com/rbuchberger/objective_elements/compare/v1.0.0...v1.1.0
75
+ [1.0.0]: https://github.com/rbuchberger/objective_elements/releases/tag/v1.0.0
data/Gemfile CHANGED
@@ -1,6 +1,9 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ source 'https://rubygems.org'
4
4
 
5
- # Specify your gem's dependencies in elements.gemspec
6
5
  gemspec
6
+
7
+ gem 'rake', '~> 13.0'
8
+ gem 'rspec', '~> 3.13'
9
+ gem 'rubocop', '~> 1.81'
data/README.md CHANGED
@@ -18,7 +18,7 @@ you only need sometimes, it turns into a horrible mess.
18
18
 
19
19
  The problem, of course, is that building long, complex, varying blocks of text with string
20
20
  concatenation and interpolation is fragile, unreadable, and painful. You know this, but you're not
21
- going to write an entirely new class or pull in some big new dependency just for 10 lines of HTML,
21
+ going to write an entirely new class or pull in some big new dependency just for 10 lines of HTML,
22
22
  so instead you hammer through it and end up with code like this:
23
23
 
24
24
  ```ruby
@@ -29,7 +29,8 @@ picture_tag = "<picture>\n"\
29
29
  "#{html_attr_string}>\n"\"#{markdown_escape * 2}</picture>\n"
30
30
  ```
31
31
 
32
- or this:
32
+ or this:
33
+
33
34
  ```ruby
34
35
  def build_li(this_item_data, icon_location, label)
35
36
  li = " <li#{@attributes['li']}>"
@@ -98,43 +99,46 @@ div = p.add_parent DoubleTag.new 'div'
98
99
 
99
100
  ## Changes
100
101
 
101
- ### 1.1.0
102
- Add `ShelfTag`, which is useful when you want to create siblings without a parent element.
103
-
104
- ### 1.0.0
105
- Attributes syntax has changed pretty significantly. Find `.add_attributes` & replace `.attributes << `
106
- will get you most of the way there, but you should read over the usage section again.
102
+ See [CHANGELOG.md](CHANGELOG.md).
107
103
 
108
104
  ## Installation
109
105
 
110
- ```ruby
111
- # Gemfile
112
-
113
- gem 'objective_elements', '~> 1.0.0'
114
- ```
115
-
116
- ```ruby
117
- # Anywhere else:
118
-
119
- require 'objective_elements'
120
- ```
121
-
106
+ ```ruby
107
+ # Gemfile
108
+
109
+ gem 'objective_elements', '~> 2.0'
110
+ ```
111
+
112
+ ```ruby
113
+ # Anywhere else:
114
+
115
+ require 'objective_elements'
116
+ ```
117
+
118
+ ### Supported Rubies
119
+
120
+ Ruby 3.0 and up, with no upper bound. The policy is to support every non-EOL Ruby, plus EOL versions
121
+ still shipped in a supported Ubuntu LTS — which is the only reason the floor is as low as 3.0. It
122
+ rises to 3.2 when Ubuntu 22.04 leaves standard support in April 2027. See
123
+ [ADR 0001](docs/adr/0001-ruby-version-support-policy.md).
124
+
122
125
  ## Terminology
123
126
 
124
127
  ```
125
128
  <p class="stumpy">Hello</p>
126
129
  |a| b | c | d |
127
130
  ```
128
- - a - element
129
- - b - attributes
130
- - a+b - opening tag
131
- - c - content
132
- - d - closing tag
133
131
 
132
+ - a - element
133
+ - b - attributes
134
+ - a+b - opening tag
135
+ - c - content
136
+ - d - closing tag
134
137
 
135
138
  ## Usage
136
139
 
137
140
  For Attribute & SingleTag examples, we'll use this image tag:
141
+
138
142
  ```ruby
139
143
 
140
144
  img = SingleTag.new 'img', attributes: 'src="angry-baby.jpg"'
@@ -146,34 +150,39 @@ A `SingleTag` is a self-closing tag, meaning it has no content and no closing ta
146
150
  the other kind.
147
151
 
148
152
  ### Attributes
153
+
149
154
  Attributes are their own class, and can be accessed by the `.attributes` method on both single and
150
155
  double tags. Important methods:
151
156
 
152
- ` << (attribute)`
157
+ `<< (attribute)`
158
+
153
159
  - Example: `p.attributes << 'alt="he does not look happy"'`
154
160
  - Example: `p.attributes << { alt: "he does not look happy" }`
155
161
  - Add new attributes, can accept a hash or a string. Hash keys will be converted
156
- to symbols if they are not already, and values will be split on spaces into an array if they are not
157
- already. Attributes can also be given as a string in the standard HTML syntax (`class="myclass"
158
- id="my-id"`). **Every other method which adds attributes in some way, calls this method**. This
159
- means that any time you are adding attributes, you can use any format which this method understands.
160
-
161
- `.delete(attribute)`
162
+ to symbols if they are not already, and values will be split on spaces into an array if they are not
163
+ already. Attributes can also be given as a string in the standard HTML syntax (`class="myclass" id="my-id"`). **Every other method which adds attributes in some way, calls this method**. This
164
+ means that any time you are adding attributes, you can use any format which this method understands.
165
+
166
+ `.delete(attribute)`
167
+
162
168
  - Example: `img.attributes.delete 'src'`
163
169
  - Example: `img.attributes.delete :src`
164
170
  - Example: `img.attributes.delete [:src, 'alt']`
165
171
  - Delete one or more attributes. Accepts a string, symbol, or an array of
166
- strings and/or symbols.
172
+ strings and/or symbols.
173
+
174
+ `.replace(attribute)`
167
175
 
168
- `.replace(attribute)`
169
176
  - Example: `img.attributes.replace 'src="happy-baby.jpg"'`
170
177
  - Replaces one or more attributes and values individually.
171
178
 
172
- `.content[:attribute_name] = `
179
+ `.content[:attribute_name] =`
180
+
173
181
  - Example: `img.attributes.content[:src] = 'dirty-baby.jpg'` < This just broke everything.
174
- - Don't do it. Use `.replace`, `.(attribute name) = `, or `<<`
182
+ - Don't do it. Use `.replace`, `.(attribute name) =`, or `<<`
183
+
184
+ `.content[:attribute_name]`
175
185
 
176
- `.content[:attribute_name]`
177
186
  - Example: `img.attributes[:src] # returns 'angry-baby.jpg`
178
187
  - Retrieve the content for a given attribute, as an array of strings. Must be a symbol. You'll
179
188
  - mostly need this when you don't know which attribute you need ahead of
@@ -181,18 +190,20 @@ strings and/or symbols.
181
190
 
182
191
  **There is a shorthand for the next two methods. Keep reading.**
183
192
 
184
- `.(attribute_name)`
193
+ `.(attribute_name)`
194
+
185
195
  - Example: `img.attributes.src # 'angry-baby.jpg'`
186
196
  - Convenience method/syntactic sugar: Returns the value of a given attribute name, as a
187
197
  - space-separated string. This relies on method_missing, which means that any overlap with
188
- already existing methods won't work.
198
+ already existing methods won't work.
189
199
  - **You can't access `class` or `method` html attributes this way, because
190
200
  basic objects in ruby already have those methods.**
191
201
  - **Ruby methods can't have dashes in them.** This means `p.data-awesomeness` won't work.
192
202
 
193
- `.(attribute_name) = value`
203
+ `.(attribute_name) = value`
204
+
194
205
  - Example: `img.attributes.src = 'happy-baby.jpg'`
195
- - Same as above. Similar to `.replace(attribute)`. Interestingly, `method = ` and `class = ` both
206
+ - Same as above. Similar to `.replace(attribute)`. Interestingly, `method =` and `class =` both
196
207
  work (`.class` is defined on the basic object class, but `.class=` is not.). Still, you
197
208
  probably shouldn't use them.
198
209
 
@@ -203,36 +214,43 @@ strings and/or symbols.
203
214
 
204
215
  ### SingleTag Properties:
205
216
 
206
- #### element
207
- - String
208
- - Mandatory
209
- - Which type of tag, such as 'hr' or 'img'
210
-
211
- #### attributes
212
- - Instance of the class described above.
217
+ #### element
218
+
219
+ - String
220
+ - Mandatory
221
+ - Which type of tag, such as 'hr' or 'img'
222
+
223
+ #### attributes
224
+
225
+ - Instance of the class described above.
213
226
 
214
227
  ### SingleTag Methods (that you care about)
215
228
 
216
229
  `SingleTag.new(element, attributes: nil)`
217
230
 
218
- `.to_s`
231
+ `.to_s`
232
+
219
233
  - Example: `img.to_s`
220
234
  - The big one. Returns your HTML as a string, nondestructively.
221
235
 
222
- `.add_parent(DoubleTag)`
236
+ `.add_parent(DoubleTag)`
237
+
223
238
  - Example: `img.add_parent DoubleTag.new 'picture'`
224
239
  - returns supplied DoubleTag, with self added as a child.
225
240
 
226
- `.attributes`
241
+ `.attributes`
242
+
227
243
  - Example: `img.attributes`
228
244
  - attr_reader for HTML attributes. This is how you can access any attribute method
229
- described above.
245
+ described above.
246
+
247
+ `.reset_attributes`
230
248
 
231
- `.reset_attributes`
232
249
  - Example: `img.reset_attributes`
233
250
  - Removes all attributes.
234
251
 
235
- `.attributes=(new)`
252
+ `.attributes=(new)`
253
+
236
254
  - Example: `img.attributes = 'src="grumpy-baby.jpg" id="muddy"'`
237
255
  - Equivalent to `reset_attributes` and `.attributes << new`
238
256
 
@@ -241,40 +259,43 @@ described above.
241
259
 
242
260
  ### DoubleTag Properties:
243
261
 
244
-
245
262
  #### `DoubleTag` Inherits all of `SingleTag`'s properties and methods, and adds content and a
263
+
246
264
  closing tag.
247
265
 
248
- #### content
266
+ #### content
249
267
 
250
- - Array
251
- - Optional
252
- - Contains anything (but probably just strings and tags. Anything else will be turned into a
253
- string with `.to_s`, which is an alias for `.inspect` most of the time).
254
- - Each element in the array corresponds to at least one line of HTML
255
- - Multiline child tags will get as many lines as they need (like you'd expect).
256
- - Child elements are not rendered until the parent is rendered, meaning you can access and
257
- modify them after defining a parent.
258
- - add with `.add_content`, or modify the content array directly.
268
+ - Array
269
+ - Optional
270
+ - Contains anything (but probably just strings and tags. Anything else will be turned into a
271
+ string with `.to_s`, which is an alias for `.inspect` most of the time).
272
+ - Each element in the array corresponds to at least one line of HTML
273
+ - Multiline child tags will get as many lines as they need (like you'd expect).
274
+ - Child elements are not rendered until the parent is rendered, meaning you can access and
275
+ modify them after defining a parent.
276
+ - add with `.add_content`, or modify the content array directly.
259
277
 
260
- #### oneline
261
- - Boolean
262
- - optional, defaults to false.
263
- - When true, the entire element and its content will be rendered as a single line. Useful for
264
- anchor tags and list items.
278
+ #### oneline
279
+
280
+ - Boolean
281
+ - optional, defaults to false.
282
+ - When true, the entire element and its content will be rendered as a single line. Useful for
283
+ anchor tags and list items.
265
284
 
266
285
  ### DoubleTag Methods (that you care about)
267
286
 
268
- For DoubleTag Examples, we're working with a div tag:
287
+ For DoubleTag Examples, we're working with a div tag:
269
288
 
270
289
  ```
271
290
  div = DoubleTag.new 'div'
272
291
  ```
273
292
 
274
- `DoubleTag.new(element, attributes: {}, oneline: false, content: [])`
293
+ `DoubleTag.new(element, attributes: {}, oneline: false, content: [])`
294
+
275
295
  - You can initialize it with content.
276
296
 
277
- `add_content(anything)`
297
+ `add_content(anything)`
298
+
278
299
  - Example: `div.add_content 'example text!'`
279
300
  - Example: `div.add_content ['splits', 'across', 'lines']`
280
301
  - Example: `div.add_content img # image tag from earlier`
@@ -300,91 +321,105 @@ tag.
300
321
  Convert it into an actual tag with `.add_parent(DoubleTag)`
301
322
 
302
323
  ## Configuration
303
-
304
- Indentation is defined by the `indent` method on the DoubleTag class, which is two escaped
305
- spaces by default ("\ \ "). If you'd like to change it:
306
324
 
307
- 1. Make a new class, inherit from DoubleTag.
308
- 2. Override `indent` with whatever you want.
309
- 3. Use your new class instead of DoubleTag.
325
+ Indentation is defined by the `indent` method on the DoubleTag class, which is two escaped
326
+ spaces by default ("\ \ "). If you'd like to change it:
327
+
328
+ 1. Make a new class, inherit from DoubleTag.
329
+ 2. Override `indent` with whatever you want.
330
+ 3. Use your new class instead of DoubleTag.
331
+
332
+ Example:
310
333
 
311
- Example:
334
+ ```ruby
312
335
 
313
- ```ruby
314
-
315
- require 'objective_elements'
336
+ require 'objective_elements'
316
337
 
317
- class MyDoubleTag < DoubleTag
318
- def indent
319
- # 4 escaped spaces:
320
- "\ \ \ \ "
321
- end
338
+ class MyDoubleTag < DoubleTag
339
+ def indent
340
+ # 4 escaped spaces:
341
+ "\ \ \ \ "
322
342
  end
343
+ end
323
344
 
324
345
  MyDoubleTag.new('p', content: 'hello').to_s
325
346
  # <p>
326
347
  # hello
327
348
  # </p>
328
349
 
329
- ```
330
-
331
- ## Limitations
332
-
333
- * It doesn't know a single HTML element on its own, so it does nothing to ensure your HTML is valid.
334
-
335
- * A parent tag can't put siblings on the same line. You can either do this (with `oneline: true` on
336
- the strong tag):
350
+ ```
337
351
 
338
- ```html
352
+ ## Limitations
339
353
 
340
- <p>
341
- Here is some
342
- <strong>strong</strong>
343
- text.
344
- </p>
354
+ - It doesn't know a single HTML element on its own, so it does nothing to ensure your HTML is valid.
345
355
 
346
- ```
347
- or this (default behavior):
356
+ - A parent tag can't put siblings on the same line. You can either do this (with `oneline: true` on
357
+ the strong tag):
348
358
 
349
- ```html
359
+ ```html
360
+ <p>
361
+ Here is some
362
+ <strong>strong</strong>
363
+ text.
364
+ </p>
365
+ ```
350
366
 
351
- <p>
352
- Here is some
353
- <strong>
354
- strong
355
- </strong>
356
- text.
357
- </p>
367
+ or this (default behavior):
358
368
 
359
- ```
360
- But you can't do this without string interpolation or something:
369
+ ```html
370
+ <p>
371
+ Here is some
372
+ <strong>
373
+ strong
374
+ </strong>
375
+ text.
376
+ </p>
377
+ ```
361
378
 
362
- ```html
379
+ But you can't do this without string interpolation or something:
363
380
 
364
- <p>Here is some <strong>strong</strong> text.</p>
381
+ ```html
382
+ <p>
383
+ Here is some
384
+ <strong>strong</strong>
385
+ text.
386
+ </p>
387
+ ```
365
388
 
366
- ```
367
- This doesn't affect how the browser will render it, but it might bug you if you're particular about
368
- source code layout.
389
+ This doesn't affect how the browser will render it, but it might bug you if you're particular about
390
+ source code layout.
369
391
 
370
- * If you set 'oneline: true' on a parent DoubleTag, but not all its children DoubleTags, the output
392
+ - If you set 'oneline: true' on a parent DoubleTag, but not all its children DoubleTags, the output
371
393
  will not be pretty. I advise against it. Handling this situation is on the TODO list.
372
394
 
373
- * It doesn't wrap long lines of text, and it doesn't indent text with newlines embedded. It's on the
395
+ - It doesn't wrap long lines of text, and it doesn't indent text with newlines embedded. It's on the
374
396
  TODO list.
375
397
 
376
- ## Contributing
398
+ ## Development
399
+
400
+ Ruby is managed with [mise](https://mise.jdx.dev/); `mise.toml` pins 3.4, which is the version CI
401
+ lints on, so local rubocop can't disagree with CI. Any supported Ruby will run the tests.
402
+
403
+ ```sh
404
+ mise install # optional; only if you use mise
405
+ bundle install
406
+ bundle exec rake # rspec + rubocop
407
+ ```
408
+ [Scoped commits](https://scopedcommits.com/)
377
409
 
378
- For code style, I've been using rubocop with the default settings and would appreciate if you did the
379
- same.
410
+ ## AI Policy
380
411
 
381
- If you add new functionality, or change existing functionality, please update the rspec tests to
382
- reflect it.
412
+ The use of LLM powered coding tools is permitted so long as:
383
413
 
384
- https://github.com/rbuchberger/objective_elements
414
+ * Any commits with any AI generated code have a trailer: `Assisted-by: <model>`
415
+ * All changes are read completely and reviewed thoroughly by a knowledgable human before merging to
416
+ master. This has always been the case, but it is especially true for AI-generated code.
417
+ * Pull request authors are expected to have done the same before submitting.
385
418
 
386
- contact:
387
- robert@robert-buchberger.com
419
+ If you don't want to run AI generated code, you can use versions prior to `2.0.0`. You are likely
420
+ using this project as a dependency of jekyll_picture_tag; it is pinned to OE `1.x` for JPT versions
421
+ prior to `3.0.0` which carries a similar policy change. In other words, If you use the non-ai
422
+ version of JPT, you'll get the non-ai version of this.
388
423
 
389
424
  ## License
390
425
 
data/Rakefile CHANGED
@@ -1,2 +1,10 @@
1
- require "bundler/gem_tasks"
2
- task :default => :spec
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rubocop/rake_task'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RuboCop::RakeTask.new
8
+ RSpec::Core::RakeTask.new(:spec)
9
+
10
+ task default: %i[spec rubocop]
data/bin/console CHANGED
@@ -1,14 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require "bundler/setup"
4
- require "elements"
4
+ require 'bundler/setup'
5
+ require 'objective_elements'
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
8
9
 
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
10
+ require 'irb'
14
11
  IRB.start(__FILE__)
@@ -0,0 +1,68 @@
1
+ # 1. Ruby version support policy
2
+
3
+ Date: 2026-08-11
4
+
5
+ ## Status
6
+
7
+ Accepted. The Ruby 3.0 floor expires April 2027 — see "Consequences".
8
+
9
+ ## Context
10
+
11
+ The gem sat dormant long enough that its tooling and its implicit Ruby support
12
+ window had both drifted. Reviving it meant answering a question that had never
13
+ been written down: which Rubies does this gem promise to work on?
14
+
15
+ Two failure modes were on the table. Setting the floor too high strands users on
16
+ distro-packaged Rubies they don't control. Setting an upper bound strands
17
+ everyone the moment a new Ruby ships — which is exactly the state
18
+ `jekyll_picture_tag` is in, uninstallable on Ruby 4.0 because of its own
19
+ `< 4.0` cap.
20
+
21
+ This gem is ~100 lines, has no runtime dependencies, and uses no recent syntax.
22
+ The cost of supporting an old Ruby is close to zero; the cost of an upper bound
23
+ is a broken install.
24
+
25
+ ## Decision
26
+
27
+ `required_ruby_version = '>= 3.0'`, with no upper bound.
28
+
29
+ The rule behind that number: **support every non-EOL Ruby, plus EOL versions
30
+ still shipped in a supported Ubuntu LTS.**
31
+
32
+ | Ruby | Status (Aug 2026) | Ubuntu LTS |
33
+ | ---- | ----------------- | --------------------- |
34
+ | 4.0 | supported | — |
35
+ | 3.4 | supported | — |
36
+ | 3.3 | supported | 26.04 |
37
+ | 3.2 | EOL 2026-03 | 24.04 (to Apr 2029) |
38
+ | 3.0 | EOL 2024-04 | 22.04 (to Apr 2027) |
39
+
40
+ No upper bound. A dependency-free library has nothing to break against a new
41
+ Ruby that a cap would protect against, and a cap guarantees breakage the day
42
+ that Ruby ships.
43
+
44
+ CI tests the full supported range — 3.0, 3.2, 3.3, 3.4, 4.0 — plus a
45
+ `continue-on-error` `ruby-head` leg for early warning. The 3.0 leg pins
46
+ `ubuntu-22.04`, because `setup-ruby` publishes no 3.0 build for newer images.
47
+ Rubocop runs once, on 3.4, matching the version `mise.toml` pins so local lint
48
+ and CI lint cannot disagree. No JRuby or TruffleRuby: no runtime dependencies
49
+ and no C extensions means nothing platform-specific to catch.
50
+
51
+ ## Consequences
52
+
53
+ The floor is user-visible metadata, so raising it is a breaking change. That is
54
+ what makes this release 2.0.0.
55
+
56
+ Ruby 3.0 is here **only** because Ubuntu 22.04 ships it. **Revisit in April
57
+ 2027**, when 22.04 leaves standard support: at that point the floor should rise
58
+ to 3.2 (Ubuntu 24.04's Ruby, supported until April 2029) in the next major
59
+ version.
60
+
61
+ Applying the rule mechanically means the floor moves on Ubuntu LTS's schedule
62
+ rather than upstream Ruby's, which is slower than most gems — deliberately.
63
+ That is the point: the users least able to upgrade Ruby are the ones on a
64
+ distro-packaged one.
65
+
66
+ Out of scope, and tracked separately in that repo: `jekyll_picture_tag`'s own
67
+ `< 4.0` cap, and its `objective_elements ~> 1.1` constraint. Both need their own
68
+ support decision.
@@ -0,0 +1,51 @@
1
+ # Domain Docs
2
+
3
+ How the engineering skills should consume this repo's domain documentation when exploring the codebase.
4
+
5
+ ## Before exploring, read these
6
+
7
+ - **`CONTEXT.md`** at the repo root, or
8
+ - **`CONTEXT-MAP.md`** at the repo root if it exists — it points at one `CONTEXT.md` per context. Read each one relevant to the topic.
9
+ - **`docs/adr/`** — read ADRs that touch the area you're about to work in. In multi-context repos, also check `src/<context>/docs/adr/` for context-scoped decisions.
10
+
11
+ If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The `/domain-modeling` skill (reached via `/grill-with-docs` and `/improve-codebase-architecture`) creates them lazily when terms or decisions actually get resolved.
12
+
13
+ ## File structure
14
+
15
+ Single-context repo (most repos):
16
+
17
+ ```
18
+ /
19
+ ├── CONTEXT.md
20
+ ├── docs/adr/
21
+ │ ├── 0001-event-sourced-orders.md
22
+ │ └── 0002-postgres-for-write-model.md
23
+ └── src/
24
+ ```
25
+
26
+ Multi-context repo (presence of `CONTEXT-MAP.md` at the root):
27
+
28
+ ```
29
+ /
30
+ ├── CONTEXT-MAP.md
31
+ ├── docs/adr/ ← system-wide decisions
32
+ └── src/
33
+ ├── ordering/
34
+ │ ├── CONTEXT.md
35
+ │ └── docs/adr/ ← context-specific decisions
36
+ └── billing/
37
+ ├── CONTEXT.md
38
+ └── docs/adr/
39
+ ```
40
+
41
+ ## Use the glossary's vocabulary
42
+
43
+ When your output names a domain concept (in an issue title, a refactor proposal, a hypothesis, a test name), use the term as defined in `CONTEXT.md`. Don't drift to synonyms the glossary explicitly avoids.
44
+
45
+ If the concept you need isn't in the glossary yet, that's a signal — either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for `/domain-modeling`).
46
+
47
+ ## Flag ADR conflicts
48
+
49
+ If your output contradicts an existing ADR, surface it explicitly rather than silently overriding:
50
+
51
+ > _Contradicts ADR-0007 (event-sourced orders) — but worth reopening because…_
@@ -0,0 +1,45 @@
1
+ # Issue tracker: GitHub
2
+
3
+ Issues and specs for this repo live as GitHub issues. Use the `gh` CLI for all operations.
4
+
5
+ ## Conventions
6
+
7
+ - **Create an issue**: `gh issue create --title "..." --body "..."`. Use a heredoc for multi-line bodies.
8
+ - **Read an issue**: `gh issue view <number> --comments`, filtering comments by `jq` and also fetching labels.
9
+ - **List issues**: `gh issue list --state open --json number,title,body,labels,comments --jq '[.[] | {number, title, body, labels: [.labels[].name], comments: [.comments[].body]}]'` with appropriate `--label` and `--state` filters.
10
+ - **Comment on an issue**: `gh issue comment <number> --body "..."`
11
+ - **Apply / remove labels**: `gh issue edit <number> --add-label "..."` / `--remove-label "..."`
12
+ - **Close**: `gh issue close <number> --comment "..."`
13
+
14
+ Infer the repo from `git remote -v` — `gh` does this automatically when run inside a clone.
15
+
16
+ ## Pull requests as a triage surface
17
+
18
+ **PRs as a request surface: no.** _(Set to `yes` if this repo treats external PRs as feature requests; `/triage` reads this flag.)_
19
+
20
+ When set to `yes`, PRs run through the same labels and states as issues, using the `gh pr` equivalents:
21
+
22
+ - **Read a PR**: `gh pr view <number> --comments` and `gh pr diff <number>` for the diff.
23
+ - **List external PRs for triage**: `gh pr list --state open --json number,title,body,labels,author,authorAssociation,comments` then keep only `authorAssociation` of `CONTRIBUTOR`, `FIRST_TIME_CONTRIBUTOR`, or `NONE` (drop `OWNER`/`MEMBER`/`COLLABORATOR`).
24
+ - **Comment / label / close**: `gh pr comment`, `gh pr edit --add-label`/`--remove-label`, `gh pr close`.
25
+
26
+ GitHub shares one number space across issues and PRs, so a bare `#42` may be either — resolve with `gh pr view 42` and fall back to `gh issue view 42`.
27
+
28
+ ## When a skill says "publish to the issue tracker"
29
+
30
+ Create a GitHub issue.
31
+
32
+ ## When a skill says "fetch the relevant ticket"
33
+
34
+ Run `gh issue view <number> --comments`.
35
+
36
+ ## Wayfinding operations
37
+
38
+ Used by `/wayfinder`. The **map** is a single issue with **child** issues as tickets.
39
+
40
+ - **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `gh issue create --label wayfinder:map`.
41
+ - **Child ticket**: an issue linked to the map as a GitHub sub-issue (`gh api` on the sub-issues endpoint). Where sub-issues aren't enabled, add the child to a task list in the map body and put `Part of #<map>` at the top of the child body. Labels: `wayfinder:<type>` (`research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev.
42
+ - **Blocking**: GitHub's **native issue dependencies** — the canonical, UI-visible representation. Add an edge with `gh api --method POST repos/<owner>/<repo>/issues/<child>/dependencies/blocked_by -F issue_id=<blocker-db-id>`, where `<blocker-db-id>` is the blocker's numeric **database id** (`gh api repos/<owner>/<repo>/issues/<n> --jq .id`, _not_ the `#number` or `node_id`). GitHub reports `issue_dependencies_summary.blocked_by` (open blockers only — the live gate). Where dependencies aren't available, fall back to a `Blocked by: #<n>, #<n>` line at the top of the child body. A ticket is unblocked when every blocker is closed.
43
+ - **Frontier query**: list the map's open children (`gh issue list --state open`, scoped to the map's sub-issues / task list), drop any with an open blocker (`issue_dependencies_summary.blocked_by > 0`, or an open issue in the `Blocked by` line) or an assignee; first in map order wins.
44
+ - **Claim**: `gh issue edit <n> --add-assignee @me` — the session's first write.
45
+ - **Resolve**: `gh issue comment <n> --body "<answer>"`, then `gh issue close <n>`, then append a context pointer (gist + link) to the map's Decisions-so-far.
@@ -0,0 +1,15 @@
1
+ # Triage Labels
2
+
3
+ The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker.
4
+
5
+ | Label in mattpocock/skills | Label in our tracker | Meaning |
6
+ | -------------------------- | -------------------- | ---------------------------------------- |
7
+ | `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue |
8
+ | `needs-info` | `needs-info` | Waiting on reporter for more information |
9
+ | `ready-for-agent` | `ready-for-agent` | Fully specified, ready for an AFK agent |
10
+ | `ready-for-human` | `ready-for-human` | Requires human implementation |
11
+ | `wontfix` | `wontfix` | Will not be actioned |
12
+
13
+ When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table.
14
+
15
+ Edit the right-hand column to match whatever vocabulary you actually use.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Non-Self-Closing tag. Can have content, but doesn't have to.
2
4
  class DoubleTag < SingleTag
3
5
  attr_accessor :oneline
@@ -29,23 +31,23 @@ class DoubleTag < SingleTag
29
31
 
30
32
  def to_a
31
33
  lines = content.map { |c| build_content_line c }
32
- lines = lines.flatten.map { |l| l.prepend oneline ? '' : indent }
34
+ lines = lines.flatten.map { |l| oneline ? l : indent + l }
33
35
  lines.unshift(opening_tag).push(closing_tag)
34
36
  end
35
37
 
36
38
  def to_s
37
- to_a.join(oneline ? '' : "\n") + "\n"
39
+ "#{to_a.join(oneline ? '' : "\n")}\n"
38
40
  end
39
41
 
40
42
  private
41
43
 
42
44
  def build_content_line(element)
43
45
  # Since DoubleTag inherits from SingleTag, it will slurp up those too.
44
- element.is_a?(SingleTag) ? element.to_a : element.to_s.dup
46
+ element.is_a?(SingleTag) ? element.to_a : element.to_s
45
47
  end
46
48
 
47
49
  def indent
48
- "\ \ "
50
+ ' '
49
51
  end
50
52
 
51
53
  def closing_tag
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Represents standard HTML attributes, such as class="myclass"
2
4
  class HTMLAttributes
3
5
  attr_reader :content
6
+
4
7
  def initialize(new = nil)
5
8
  @content = {}
6
9
  self << new
@@ -11,12 +14,9 @@ class HTMLAttributes
11
14
  end
12
15
 
13
16
  def to_s
14
- return_string = ''
15
- @content.each_pair do |k, v|
16
- return_string << "#{k}=\"#{v.join ' '}\" "
17
- end
18
-
19
- return_string.strip
17
+ # An attribute with no values joins to an empty string, which is the
18
+ # correct format (alt="", for example).
19
+ @content.map { |k, v| "#{k}=\"#{v.join ' '}\"" }.join(' ')
20
20
  end
21
21
 
22
22
  # This is the only way we add new attributes. Flexible about what you give
@@ -86,29 +86,36 @@ class HTMLAttributes
86
86
  add_hash hashify_input new_string
87
87
  end
88
88
 
89
- def add_hash(new)
89
+ # Input: Keys are attribute names (either strings or symbols), values are
90
+ # attribute values (either a string or an array of strings)
91
+ def add_hash(new_hash)
90
92
  formatted_new = {}
91
- new.each_pair do |k, v|
92
- v = v.split ' ' if v.is_a? String
93
+
94
+ new_hash.each_pair do |k, v|
95
+ v = v.split if v.is_a? String
96
+
93
97
  formatted_new[k.to_sym] = v
94
98
  end
95
99
 
96
- @content.merge! formatted_new do |_key, oldval, newval|
97
- oldval.concat newval
100
+ @content.merge!(formatted_new) do |_key, oldval, newval|
101
+ oldval.concat(newval)
98
102
  end
103
+
99
104
  self
100
105
  end
101
106
 
102
107
  def hashify_input(new_string)
103
108
  # looking for something like:
104
- # 'class="something something-else" id="my-id"'
109
+ # 'class="something something-else" id="my-id" alt=""'
105
110
  new_hash = {}
106
- new_string.scan(/ ?([^="]+)="([^"]+)"/).each do |m|
107
- # [['class','something something-else'],['id','my-id']]
108
- key = m.shift
109
- val = m.pop
111
+ new_string.scan(/ ?([^="]+)="([^"]*)"/).each do |match|
112
+ # Returns something like:
113
+ # [['class','something something-else'],['id','my-id'],['alt', '']]
114
+
115
+ key, val = *match
116
+
110
117
  if new_hash[key]
111
- new_hash[key] << ' ' + val
118
+ new_hash[key] << " #{val}"
112
119
  else
113
120
  new_hash[key] = val
114
121
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This is a nonexistent HTML tag, which holds content like a double tag but has
2
4
  # no opening or closing tag. This allows us to group siblings without adding an
3
5
  # extra parent to the markup.
4
6
  class ShelfTag < DoubleTag
7
+ # A shelf has no element of its own, so it never renders an opening tag.
5
8
  def initialize(content: nil, oneline: false)
6
- self.oneline = oneline
7
- self.content = content
9
+ super(nil, content: content, oneline: oneline)
8
10
  end
9
11
 
10
12
  def to_a
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Collection of HTML element tags
2
4
  # Describes a basic, self-closing HTML tag.
3
5
  class SingleTag
@@ -34,7 +36,7 @@ class SingleTag
34
36
 
35
37
  # Renders our HTML.
36
38
  def to_s
37
- opening_tag + "\n"
39
+ "#{opening_tag}\n"
38
40
  end
39
41
 
40
42
  # Allows us to work with attributes as methods:
@@ -53,8 +55,8 @@ class SingleTag
53
55
  private
54
56
 
55
57
  def opening_tag
56
- output = '<' + @element
57
- output << ' ' + @attributes.to_s unless @attributes.empty?
58
- output << '>'
58
+ return "<#{@element}>" if @attributes.empty?
59
+
60
+ "<#{@element} #{@attributes}>"
59
61
  end
60
62
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ObjectiveElements
2
- VERSION = '1.1.1'.freeze
4
+ VERSION = '2.0.0'
3
5
  end
@@ -1,3 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Author: Robert Buchberger <robert@buchberger.cc>
4
+ #
5
+ # This module provides a few helpful classes for generating HTML using simple
6
+ # Ruby. Its goal is to be lightweight, and more focused than the general-purpose
7
+ # nature of nokogiri.
1
8
  module ObjectiveElements
2
9
  require_relative 'objective_elements/single_tag'
3
10
  require_relative 'objective_elements/double_tag'
data/mise.toml ADDED
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = "3.4"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  lib = File.expand_path('lib', __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require 'objective_elements/version'
@@ -6,12 +8,22 @@ Gem::Specification.new do |spec|
6
8
  spec.name = 'objective_elements'
7
9
  spec.version = ObjectiveElements::VERSION
8
10
  spec.authors = ['Robert Buchberger']
9
- spec.email = ['robert@robert-buchberger.com']
11
+ spec.email = ['robert@buchberger.cc']
10
12
 
11
- spec.summary = 'Build HTML without interpolating strings.'
13
+ spec.summary = 'Build HTML with simple ruby.'
12
14
  spec.homepage = 'https://github.com/rbuchberger/objective_elements'
13
15
  spec.license = 'MIT'
14
16
 
17
+ spec.required_ruby_version = '>= 3.0'
18
+
19
+ spec.metadata = {
20
+ 'homepage_uri' => spec.homepage,
21
+ 'source_code_uri' => spec.homepage,
22
+ 'bug_tracker_uri' => "#{spec.homepage}/issues",
23
+ 'changelog_uri' => "#{spec.homepage}/blob/master/CHANGELOG.md",
24
+ 'rubygems_mfa_required' => 'true'
25
+ }
26
+
15
27
  # Specify which files should be added to the gem when it is released. The
16
28
  # `git ls-files -z` loads the files in the RubyGem that have been added into
17
29
  # git.
@@ -23,9 +35,4 @@ Gem::Specification.new do |spec|
23
35
  spec.bindir = 'exe'
24
36
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
37
  spec.require_paths = ['lib']
26
-
27
- spec.add_development_dependency 'bundler', '~> 1.16'
28
- spec.add_development_dependency 'pry', '~>0.11.3'
29
- spec.add_development_dependency 'rake', '~> 10.0'
30
- spec.add_development_dependency 'rspec', '~>3.8.0'
31
38
  end
metadata CHANGED
@@ -1,98 +1,53 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: objective_elements
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Buchberger
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2019-11-14 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.16'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.16'
27
- - !ruby/object:Gem::Dependency
28
- name: pry
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: 0.11.3
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: 0.11.3
41
- - !ruby/object:Gem::Dependency
42
- name: rake
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '10.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '10.0'
55
- - !ruby/object:Gem::Dependency
56
- name: rspec
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 3.8.0
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 3.8.0
69
- description:
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
70
12
  email:
71
- - robert@robert-buchberger.com
13
+ - robert@buchberger.cc
72
14
  executables: []
73
15
  extensions: []
74
16
  extra_rdoc_files: []
75
17
  files:
18
+ - ".github/workflows/ci.yml"
19
+ - ".github/workflows/release.yml"
76
20
  - ".gitignore"
21
+ - ".rubocop.yml"
22
+ - AGENTS.md
23
+ - CHANGELOG.md
77
24
  - Gemfile
78
- - Gemfile.lock
79
25
  - LICENSE.txt
80
26
  - README.md
81
27
  - Rakefile
82
28
  - bin/console
83
29
  - bin/setup
30
+ - docs/adr/0001-ruby-version-support-policy.md
31
+ - docs/agents/domain.md
32
+ - docs/agents/issue-tracker.md
33
+ - docs/agents/triage-labels.md
84
34
  - lib/objective_elements.rb
85
35
  - lib/objective_elements/double_tag.rb
86
36
  - lib/objective_elements/html_attributes.rb
87
37
  - lib/objective_elements/shelf_tag.rb
88
38
  - lib/objective_elements/single_tag.rb
89
39
  - lib/objective_elements/version.rb
40
+ - mise.toml
90
41
  - objective_elements.gemspec
91
42
  homepage: https://github.com/rbuchberger/objective_elements
92
43
  licenses:
93
44
  - MIT
94
- metadata: {}
95
- post_install_message:
45
+ metadata:
46
+ homepage_uri: https://github.com/rbuchberger/objective_elements
47
+ source_code_uri: https://github.com/rbuchberger/objective_elements
48
+ bug_tracker_uri: https://github.com/rbuchberger/objective_elements/issues
49
+ changelog_uri: https://github.com/rbuchberger/objective_elements/blob/master/CHANGELOG.md
50
+ rubygems_mfa_required: 'true'
96
51
  rdoc_options: []
97
52
  require_paths:
98
53
  - lib
@@ -100,15 +55,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
100
55
  requirements:
101
56
  - - ">="
102
57
  - !ruby/object:Gem::Version
103
- version: '0'
58
+ version: '3.0'
104
59
  required_rubygems_version: !ruby/object:Gem::Requirement
105
60
  requirements:
106
61
  - - ">="
107
62
  - !ruby/object:Gem::Version
108
63
  version: '0'
109
64
  requirements: []
110
- rubygems_version: 3.0.3
111
- signing_key:
65
+ rubygems_version: 3.6.9
112
66
  specification_version: 4
113
- summary: Build HTML without interpolating strings.
67
+ summary: Build HTML with simple ruby.
114
68
  test_files: []
data/Gemfile.lock DELETED
@@ -1,41 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- objective_elements (1.1.0)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- coderay (1.1.2)
10
- diff-lcs (1.3)
11
- method_source (0.9.0)
12
- pry (0.11.3)
13
- coderay (~> 1.1.0)
14
- method_source (~> 0.9.0)
15
- rake (10.5.0)
16
- rspec (3.8.0)
17
- rspec-core (~> 3.8.0)
18
- rspec-expectations (~> 3.8.0)
19
- rspec-mocks (~> 3.8.0)
20
- rspec-core (3.8.0)
21
- rspec-support (~> 3.8.0)
22
- rspec-expectations (3.8.1)
23
- diff-lcs (>= 1.2.0, < 2.0)
24
- rspec-support (~> 3.8.0)
25
- rspec-mocks (3.8.0)
26
- diff-lcs (>= 1.2.0, < 2.0)
27
- rspec-support (~> 3.8.0)
28
- rspec-support (3.8.0)
29
-
30
- PLATFORMS
31
- ruby
32
-
33
- DEPENDENCIES
34
- bundler (~> 1.16)
35
- objective_elements!
36
- pry (~> 0.11.3)
37
- rake (~> 10.0)
38
- rspec (~> 3.8.0)
39
-
40
- BUNDLED WITH
41
- 1.17.2