caution_tape 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8d9f212339a683ae0d697706a666604f581590b7fb3521f29b2cbe9beb5a8573
4
+ data.tar.gz: 589c44ac2afc6f469a2adadd2fcc277f1a8806003ea0a67f4236a0778470fe21
5
+ SHA512:
6
+ metadata.gz: 9c533b126330f28dc8094032802ce57dc65ae73476acc62e7d2a32c9deceed5ef78d09a1de2e476a9d740d47c50cee0564aa6a33af020f59bb3ac952f11fe317
7
+ data.tar.gz: b669a924ed43453ed0d04dc25625e82646c3c6ce97f7d5c6344f6886dd1c8c67aee22bc6e0d18bd523394c68f9d6a994060317c8e47973c4a2b6eb6ad6f2a547
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2026-07-15
4
+
5
+ - Initial release
@@ -0,0 +1,10 @@
1
+ # Code of Conduct
2
+
3
+ "caution_tape" follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.):
4
+
5
+ * Participants will be tolerant of opposing views.
6
+ * Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
7
+ * When interpreting the words and actions of others, participants should always assume good intentions.
8
+ * Behaviour which can be reasonably considered harassment will not be tolerated.
9
+
10
+ If you have any concerns about behaviour within this project, please contact us at ["me@jaspermayone.com"](mailto:"me@jaspermayone.com").
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Jasper Mayone
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # caution_tape 🚧
2
+
3
+ Visual environment indicators for Rack and Rails apps. Wraps non-production
4
+ environments in unmistakable chrome — a striped construction frame and warning
5
+ banner for staging/sandbox, a solid colored frame for development — so nobody
6
+ ever mistakes a test environment for production (or puts production data in a
7
+ sandbox).
8
+
9
+ - Zero assets, zero JavaScript — a Rack middleware injects a small inline
10
+ `<style>` + two `<div>`s before `</body>` on HTML responses.
11
+ - Click-through (`pointer-events: none`) — never blocks the UI.
12
+ - Off by default — production is safe unless you explicitly enable it.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ bundle add caution_tape
18
+ ```
19
+
20
+ ## Usage (Rails)
21
+
22
+ The Railtie installs the middleware automatically. Enable and style it per
23
+ environment:
24
+
25
+ ```ruby
26
+ # config/environments/development.rb
27
+ CautionTape.configure do |c|
28
+ c.enabled = true
29
+ c.style = :solid
30
+ c.color = "#dc2626"
31
+ c.tag = "Dev"
32
+ end
33
+ ```
34
+
35
+ ```ruby
36
+ # config/environments/production.rb — same image serves prod and sandbox
37
+ CautionTape.configure do |c|
38
+ c.enabled = ENV.fetch("BASE_URL", "").include?("sandbox")
39
+ c.style = :stripes
40
+ c.banner = "Sandbox — test environment. Do not enter real data."
41
+ end
42
+ ```
43
+
44
+ ## Usage (plain Rack)
45
+
46
+ ```ruby
47
+ CautionTape.configure do |c|
48
+ c.enabled = true
49
+ c.banner = "Staging"
50
+ end
51
+
52
+ use CautionTape::Middleware
53
+ run MyApp
54
+ ```
55
+
56
+ ## Configuration
57
+
58
+ | Option | Default | Notes |
59
+ |---|---|---|
60
+ | `enabled` | `false` | Nothing renders unless enabled |
61
+ | `style` | `:stripes` | `:stripes` (caution stripes) or `:solid` |
62
+ | `color` | `"#f5c518"` | Accent color; stripes pair it with near-black |
63
+ | `banner` | `nil` | Warning pill pinned top-center |
64
+ | `tag` | `nil` | Small label pill, shown when no banner is set |
65
+ | `border_width` | `10` | Frame thickness in px |
66
+
67
+ ## Development
68
+
69
+ After checking out the repo, run `bin/setup` to install dependencies. Then run
70
+ `rake test` to run the tests. You can also run `bin/console` for an interactive
71
+ prompt.
72
+
73
+ ## Contributing
74
+
75
+ Bug reports and pull requests are welcome on GitHub at
76
+ https://github.com/singlefeather/caution_tape. Contributors are expected to
77
+ adhere to the [code of conduct](CODE_OF_CONDUCT.md).
78
+
79
+ ## License
80
+
81
+ The gem is available as open source under the terms of the
82
+ [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+ Minitest::TestTask.create
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[test rubocop]
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CautionTape
4
+ # Runtime configuration for the injected chrome.
5
+ class Configuration
6
+ STYLES = %i[stripes solid].freeze
7
+
8
+ # Whether any chrome is rendered at all. Defaults to off so production
9
+ # is safe by default — enable explicitly per environment.
10
+ attr_accessor :enabled
11
+
12
+ # :stripes — diagonal caution stripes (accent color + black).
13
+ # :solid — a plain frame in the accent color.
14
+ attr_reader :style
15
+
16
+ # Accent color. Stripes pair it with near-black; solid uses it alone.
17
+ attr_accessor :color
18
+
19
+ # Full-width warning pill pinned top-center, e.g.
20
+ # "Sandbox — do not enter real data." nil renders no banner.
21
+ attr_accessor :banner
22
+
23
+ # Small label pill (e.g. "Dev") shown when no banner is set. nil hides it.
24
+ attr_accessor :tag
25
+
26
+ # Frame thickness in px.
27
+ attr_accessor :border_width
28
+
29
+ def initialize
30
+ @enabled = false
31
+ @style = :stripes
32
+ @color = "#f5c518"
33
+ @banner = nil
34
+ @tag = nil
35
+ @border_width = 10
36
+ end
37
+
38
+ def style=(value)
39
+ value = value.to_sym
40
+ raise ArgumentError, "style must be one of #{STYLES.join(", ")}" unless STYLES.include?(value)
41
+
42
+ @style = value
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CautionTape
4
+ # Rack middleware that injects the environment chrome into HTML responses,
5
+ # just before </body>.
6
+ class Middleware
7
+ BODY_CLOSE = "</body>"
8
+
9
+ def initialize(app)
10
+ @app = app
11
+ end
12
+
13
+ def call(env)
14
+ status, headers, body = @app.call(env)
15
+ config = CautionTape.configuration
16
+ return [status, headers, body] unless config.enabled && html?(headers)
17
+
18
+ inject(status, headers, body, config)
19
+ end
20
+
21
+ private
22
+
23
+ def inject(status, headers, body, config)
24
+ original = read_body(body)
25
+ index = original.rindex(BODY_CLOSE)
26
+ return [status, headers, [original]] unless index
27
+
28
+ injected = original.dup
29
+ injected.insert(index, Renderer.html(config))
30
+ [status, update_content_length(headers, injected), [injected]]
31
+ end
32
+
33
+ def read_body(body)
34
+ buffer = +""
35
+ body.each { |chunk| buffer << chunk }
36
+ body.close if body.respond_to?(:close)
37
+ buffer
38
+ end
39
+
40
+ def update_content_length(headers, injected)
41
+ key = headers.key?("content-length") ? "content-length" : "Content-Length"
42
+ return headers unless headers.key?(key)
43
+
44
+ headers.merge(key => injected.bytesize.to_s)
45
+ end
46
+
47
+ def html?(headers)
48
+ content_type = headers["content-type"] || headers["Content-Type"]
49
+ content_type&.include?("text/html")
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CautionTape
4
+ # Auto-installs the middleware in Rails applications.
5
+ class Railtie < ::Rails::Railtie
6
+ initializer "caution_tape.middleware" do |app|
7
+ app.middleware.use CautionTape::Middleware
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CautionTape
4
+ # Builds the HTML fragment (styles + frame + banner/tag) injected into pages.
5
+ module Renderer
6
+ module_function
7
+
8
+ def html(config)
9
+ parts = [+"<style>#{css(config)}</style>"]
10
+ parts << %(<div class="caution-tape-frame" aria-hidden="true"></div>)
11
+ if config.banner
12
+ parts << %(<div class="caution-tape-banner" role="status">#{escape(config.banner)}</div>)
13
+ elsif config.tag
14
+ parts << %(<div class="caution-tape-tag" aria-hidden="true">#{escape(config.tag)}</div>)
15
+ end
16
+ parts.join
17
+ end
18
+
19
+ def css(config)
20
+ [frame_css(config), pill_css(config)].join
21
+ end
22
+
23
+ def frame_css(config)
24
+ border = if config.style == :stripes
25
+ "border:#{config.border_width}px solid;" \
26
+ "border-image:repeating-linear-gradient(45deg,#1a1a1a 0 16px," \
27
+ "#{config.color} 16px 32px) #{config.border_width};"
28
+ else
29
+ "border:#{config.border_width}px solid #{config.color};"
30
+ end
31
+ ".caution-tape-frame{position:fixed;inset:0;pointer-events:none;z-index:2147483000;#{border}}"
32
+ end
33
+
34
+ def pill_css(config)
35
+ base = "position:fixed;top:0;left:50%;transform:translateX(-50%);z-index:2147483001;" \
36
+ "pointer-events:none;font:700 12px/1.4 system-ui,sans-serif;letter-spacing:.08em;" \
37
+ "text-transform:uppercase;padding:6px 16px;border-radius:0 0 8px 8px;"
38
+ banner = ".caution-tape-banner{#{base}background:#1a1a1a;color:#{config.color};" \
39
+ "box-shadow:0 2px 8px rgba(0,0,0,.35);}"
40
+ tag = ".caution-tape-tag{#{base}background:#{config.color};color:#fff;}"
41
+ banner + tag
42
+ end
43
+
44
+ def escape(text)
45
+ text.to_s.gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;")
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CautionTape
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "caution_tape/version"
4
+ require_relative "caution_tape/configuration"
5
+ require_relative "caution_tape/renderer"
6
+ require_relative "caution_tape/middleware"
7
+ require_relative "caution_tape/railtie" if defined?(Rails::Railtie)
8
+
9
+ # Visual environment indicators for Rack and Rails apps — a striped
10
+ # construction frame and banner for sandboxes, a solid frame for dev.
11
+ module CautionTape
12
+ class Error < StandardError; end
13
+
14
+ class << self
15
+ def configuration
16
+ @configuration ||= Configuration.new
17
+ end
18
+
19
+ def configure
20
+ yield configuration
21
+ configuration
22
+ end
23
+
24
+ def reset_configuration!
25
+ @configuration = Configuration.new
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,4 @@
1
+ module CautionTape
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: caution_tape
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jasper Mayone
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rack
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '2.2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '2.2'
26
+ description: Wraps non-production environments in unmistakable visual chrome — a striped
27
+ construction frame and warning banner for staging/sandbox, a solid colored frame
28
+ for development — so nobody ever mistakes a test environment for production.
29
+ email:
30
+ - me@jaspermayone.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - CHANGELOG.md
36
+ - CODE_OF_CONDUCT.md
37
+ - LICENSE.txt
38
+ - README.md
39
+ - Rakefile
40
+ - lib/caution_tape.rb
41
+ - lib/caution_tape/configuration.rb
42
+ - lib/caution_tape/middleware.rb
43
+ - lib/caution_tape/railtie.rb
44
+ - lib/caution_tape/renderer.rb
45
+ - lib/caution_tape/version.rb
46
+ - sig/caution_tape.rbs
47
+ homepage: https://github.com/singlefeather/caution_tape
48
+ licenses:
49
+ - MIT
50
+ metadata:
51
+ homepage_uri: https://github.com/singlefeather/caution_tape
52
+ source_code_uri: https://github.com/singlefeather/caution_tape
53
+ changelog_uri: https://github.com/singlefeather/caution_tape/blob/main/CHANGELOG.md
54
+ rubygems_mfa_required: 'true'
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 3.2.0
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubygems_version: 4.0.3
70
+ specification_version: 4
71
+ summary: Visual environment indicators for Rack and Rails apps.
72
+ test_files: []