tint_me 1.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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop_todo.yml +7 -0
  3. data/.serena/project.yml +68 -0
  4. data/.simplecov +24 -0
  5. data/.yardopts +6 -0
  6. data/AGENTS.md +60 -0
  7. data/CHANGELOG.md +29 -0
  8. data/CLAUDE.md +1 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +175 -0
  11. data/RELEASING.md +202 -0
  12. data/Rakefile +18 -0
  13. data/benchmark/2025-09-08-style-caching-optimization/01_baseline_results.txt +39 -0
  14. data/benchmark/2025-09-08-style-caching-optimization/02_with_full_caching_results.txt +54 -0
  15. data/benchmark/2025-09-08-style-caching-optimization/03_prefix_only_caching_results.txt +107 -0
  16. data/benchmark/2025-09-08-style-caching-optimization/04_baseline_vs_optimized_analysis.txt +65 -0
  17. data/benchmark/2025-09-08-style-caching-optimization/05_caching_approaches_comparison.txt +59 -0
  18. data/benchmark/2025-09-08-style-caching-optimization/06_append_operator_results.txt +107 -0
  19. data/benchmark/2025-09-08-style-caching-optimization/07_string_concatenation_comparison.txt +66 -0
  20. data/benchmark/2025-09-08-style-caching-optimization/08_with_freeze_optimization_results.txt +107 -0
  21. data/benchmark/2025-09-08-style-caching-optimization/09_freeze_optimization_analysis.txt +49 -0
  22. data/benchmark/2025-09-08-style-caching-optimization/10_constant_access_results.txt +107 -0
  23. data/benchmark/2025-09-08-style-caching-optimization/11_constant_vs_cache_analysis.txt +74 -0
  24. data/benchmark/2025-09-08-style-caching-optimization/12_empty_prefix_analysis.txt +81 -0
  25. data/benchmark/2025-09-08-style-caching-optimization/13_nil_check_optimization_results.txt +107 -0
  26. data/benchmark/2025-09-08-style-caching-optimization/14_nil_vs_empty_check_analysis.txt +81 -0
  27. data/benchmark/2025-09-08-style-caching-optimization/README.md +45 -0
  28. data/benchmark/2025-09-08-style-caching-optimization/benchmark_script.rb +180 -0
  29. data/docs/agents/git-pr.md +298 -0
  30. data/docs/agents/languages.md +388 -0
  31. data/docs/agents/rubocop.md +55 -0
  32. data/lib/tint_me/error.rb +6 -0
  33. data/lib/tint_me/sgr_builder.rb +259 -0
  34. data/lib/tint_me/style/schema.rb +22 -0
  35. data/lib/tint_me/style/types.rb +50 -0
  36. data/lib/tint_me/style.rb +286 -0
  37. data/lib/tint_me/version.rb +8 -0
  38. data/lib/tint_me.rb +62 -0
  39. data/mise.toml +5 -0
  40. data/sig/tint_me.rbs +61 -0
  41. metadata +131 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 32acd1788229fa045285ea19649c993b0b4f9e59758ae92ec9a0eee630b58544
4
+ data.tar.gz: 89cfff7bc922b2fcbf876263b2a2b8dccf8762663bf15777e0b877f127d57553
5
+ SHA512:
6
+ metadata.gz: 118fa5cf809036f4169c0b7e0832fa4a90c14d92298db7f3afac16bb70bd7855200f8bed0b600369c3163a1a1a2f7d7d91c619a265a3720b030020207aeeea67
7
+ data.tar.gz: dc3e91e45584ed1c353bc28cf8d095af7a429ed0873d5aa88ea4ed2cf5e289c1e3259ac3ef24806d2147a0d2451f31dd313a3b6da4cc2aaf511cd4f538558cfe
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,7 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config --no-exclude-limit --no-offense-counts --no-auto-gen-timestamp`
3
+ # using RuboCop version 1.80.2.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
@@ -0,0 +1,68 @@
1
+ # language of the project (csharp, python, rust, java, typescript, go, cpp, or ruby)
2
+ # * For C, use cpp
3
+ # * For JavaScript, use typescript
4
+ # Special requirements:
5
+ # * csharp: Requires the presence of a .sln file in the project folder.
6
+ language: ruby
7
+
8
+ # whether to use the project's gitignore file to ignore files
9
+ # Added on 2025-04-07
10
+ ignore_all_files_in_gitignore: true
11
+ # list of additional paths to ignore
12
+ # same syntax as gitignore, so you can use * and **
13
+ # Was previously called `ignored_dirs`, please update your config if you are using that.
14
+ # Added (renamed) on 2025-04-07
15
+ ignored_paths: []
16
+
17
+ # whether the project is in read-only mode
18
+ # If set to true, all editing tools will be disabled and attempts to use them will result in an error
19
+ # Added on 2025-04-18
20
+ read_only: false
21
+
22
+
23
+ # list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
24
+ # Below is the complete list of tools for convenience.
25
+ # To make sure you have the latest list of tools, and to view their descriptions,
26
+ # execute `uv run scripts/print_tool_overview.py`.
27
+ #
28
+ # * `activate_project`: Activates a project by name.
29
+ # * `check_onboarding_performed`: Checks whether project onboarding was already performed.
30
+ # * `create_text_file`: Creates/overwrites a file in the project directory.
31
+ # * `delete_lines`: Deletes a range of lines within a file.
32
+ # * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
33
+ # * `execute_shell_command`: Executes a shell command.
34
+ # * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
35
+ # * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
36
+ # * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
37
+ # * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
38
+ # * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
39
+ # * `initial_instructions`: Gets the initial instructions for the current project.
40
+ # Should only be used in settings where the system prompt cannot be set,
41
+ # e.g. in clients you have no control over, like Claude Desktop.
42
+ # * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
43
+ # * `insert_at_line`: Inserts content at a given line in a file.
44
+ # * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
45
+ # * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
46
+ # * `list_memories`: Lists memories in Serena's project-specific memory store.
47
+ # * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
48
+ # * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
49
+ # * `read_file`: Reads a file within the project directory.
50
+ # * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
51
+ # * `remove_project`: Removes a project from the Serena configuration.
52
+ # * `replace_lines`: Replaces a range of lines within a file with new content.
53
+ # * `replace_symbol_body`: Replaces the full definition of a symbol.
54
+ # * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
55
+ # * `search_for_pattern`: Performs a search for a pattern in the project.
56
+ # * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
57
+ # * `switch_modes`: Activates modes by providing a list of their names
58
+ # * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
59
+ # * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
60
+ # * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
61
+ # * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
62
+ excluded_tools: []
63
+
64
+ # initial prompt for the project. It will always be given to the LLM upon activating the project
65
+ # (contrary to the memories, which are loaded on demand).
66
+ initial_prompt: ""
67
+
68
+ project_name: "tint_me"
data/.simplecov ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ SimpleCov.start do
4
+ # Coverage output directory
5
+ coverage_dir "coverage"
6
+
7
+ # Minimum coverage threshold
8
+ minimum_coverage 90
9
+
10
+ # Exclude files from coverage
11
+ add_filter "/spec/"
12
+ add_filter "/vendor/"
13
+ add_filter "/bin/"
14
+ add_filter "lib/tint_me/version.rb"
15
+
16
+ # Group coverage by directory
17
+ add_group "Main", "lib/tint_me"
18
+
19
+ # Coverage formats
20
+ formatter SimpleCov::Formatter::MultiFormatter.new([
21
+ SimpleCov::Formatter::HTMLFormatter,
22
+ SimpleCov::Formatter::SimpleFormatter
23
+ ])
24
+ end
data/.yardopts ADDED
@@ -0,0 +1,6 @@
1
+ --output-dir docs/api
2
+ --markup markdown
3
+ --markup-provider redcarpet
4
+ --readme README.md
5
+ --title "TIntMe! API Documentation"
6
+ lib/**/*.rb
data/AGENTS.md ADDED
@@ -0,0 +1,60 @@
1
+ # Repository Guidelines
2
+
3
+ > **Note**: This file is also accessible via the `CLAUDE.md` symlink for AI agent compatibility.
4
+
5
+ > **Important**: This document references other documentation files. Please also read:
6
+ > - `docs/agents/rubocop.md` - RuboCop fix guidelines for AI agents
7
+ > - `docs/agents/git-pr.md` - Git commit and pull request guidelines
8
+ > - `docs/agents/languages.md` - Language usage guidelines for communication and code
9
+ > - Any other documents referenced inline below
10
+
11
+ ## Project Structure & Module Organization
12
+ - `lib/tint_me`: Core library. Entry point is `lib/tint_me.rb`; code is namespaced under `TIntMe` (autoloaded via Zeitwerk).
13
+ - `spec`: RSpec tests. Mirror library paths (e.g., `spec/tint_me/style_spec.rb`).
14
+ - `docs/api`: Generated YARD documentation. Do not edit by hand; use `rake doc`.
15
+ - `benchmark/*`: Performance experiments and notes.
16
+ - `bin`: Development helpers (`bin/setup`, `bin/console`).
17
+
18
+ ## Build, Test, and Development Commands
19
+ - `bundle install`: Install dependencies (use a supported Ruby; see policy below and `mise.toml`).
20
+ - `rake`: Default task; runs `spec` and `rubocop`.
21
+ - `rake spec`: Run the test suite.
22
+ - `rubocop` or `rake rubocop`: Lint and style checks.
23
+ - `rake doc`: Build YARD docs into `docs/api`.
24
+ - `bin/console`: IRB with the gem loaded for quick experiments.
25
+ - `docquet regenerate-todo`: Regenerate `.rubocop_todo.yml` after lint updates; include with related code fixes.
26
+
27
+ ## Communication & Languages
28
+ See `docs/agents/languages.md` for detailed language usage guidelines covering:
29
+ - AI/user chat communication languages
30
+ - Source code and documentation language requirements
31
+ - Issues/PRs language preferences
32
+ - Context-appropriate language switching
33
+
34
+ ## Coding Style & Naming Conventions
35
+ - Ruby 3.x compatible; 2-space indent, `# frozen_string_literal: true` headers.
36
+ - Follow RuboCop rules (`.rubocop.yml`); fix offenses before committing.
37
+ - Files and specs use snake_case; specs live under `spec/tint_me/*_spec.rb`.
38
+ - Public API is under `TIntMe`; avoid monkey patching. Prefer immutable, composable objects (e.g., `Style` and `>>`).
39
+ - RuboCop fixes: When addressing lints, follow `docs/agents/rubocop.md` (safe autocorrect first; targeted unsafe only as needed).
40
+
41
+ ## Testing Guidelines
42
+ - Framework: RSpec with `spec_helper` and SimpleCov. Maintain ≥ 90% coverage.
43
+ - Name/spec files to mirror library paths; keep examples focused and readable.
44
+ - Run `rake spec` locally; ensure `.rspec_status` is clean.
45
+
46
+ ## Commit & Pull Request Guidelines
47
+ - Title format: Must start with a GitHub `:emoji:` code followed by a space, then an imperative subject. Example: `:zap: Optimize Style#call path`.
48
+ - No raw emoji: Use `:emoji:` codes only (commit hook rejects Unicode emoji).
49
+ - Exceptions: `fixup!` / `squash!` are allowed by hooks.
50
+ - Merge commits: Auto-prefixed with `:inbox_tray:` by the prepare-commit-msg hook.
51
+ - Commit body: English, explaining motivation, approach, and trade-offs.
52
+ - Include rationale and, when useful, before/after snippets or benchmarks.
53
+ - Link issues (e.g., `Fixes #123`) and update README/CHANGELOG when user-facing behavior changes.
54
+ - PRs must pass `rake` (tests + lint), include tests for changes, and keep API docs current (`rake doc` when needed).
55
+
56
+ ## Security & Configuration Tips
57
+ - Supported Ruby: latest patch of the newest three minor series (e.g., 3.4.x / 3.3.x / 3.2.x). Develop locally on the oldest of these.
58
+ - Version management: Use `mise`; the repo’s `mise.toml` sets the default to the oldest supported series. Examples: `mise use -g ruby@3.2`, `mise run -e ruby@3.3 rake spec`.
59
+ - Keep runtime dependencies minimal; prefer standard library where possible.
60
+ - No network access is expected at runtime; avoid introducing it without discussion.
data/CHANGELOG.md ADDED
@@ -0,0 +1,29 @@
1
+ ## [Unreleased]
2
+
3
+ ## [1.0.0] - 2025-09-09
4
+
5
+ ### Added
6
+ - Core Style class with immutable data structure using Data.define (extracted from Fasti gem)
7
+ - Support for foreground/background colors (named colors, hex values)
8
+ - Text effects: bold, faint, italic, underline (including double), overline, blink, hide, inverse
9
+ - Style composition with >> operator for layering styles
10
+ - Bold/faint mutual exclusion handling in composition
11
+ - TIntMe[] shortcut method for convenient style creation
12
+ - Style#call and Style#[] methods for applying styles to text
13
+ - Native ANSI SGR implementation with comprehensive color and effect support
14
+ - Zeitwerk autoloader with custom inflection rules for TIntMe
15
+ - Comprehensive test suite with 100% code coverage
16
+ - SimpleCov integration for coverage reporting
17
+ - YARD documentation generation with redcarpet markdown support
18
+ - RuboCop configuration with systematic violation resolution
19
+ - Rake tasks for testing, linting, and documentation generation
20
+
21
+ ### Development
22
+ - Complete project setup with proper gem structure
23
+ - Git configuration with appropriate .gitignore patterns
24
+ - Bundler gem tasks integration
25
+ - RSpec test framework with progress format output
26
+ - Development dependencies: RuboCop, YARD, SimpleCov
27
+ - Continuous integration ready configuration
28
+ - Comprehensive AI agent guidelines for Git/PR operations and language usage
29
+ - Performance guidelines for style composition optimization
data/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ AGENTS.md
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 OZAWA Sakuro
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,175 @@
1
+ # :lipstick: TIntMe! :nail_care:
2
+
3
+ A Ruby library for terminal text styling with ANSI colors and effects. TIntMe! provides an elegant and composable API for applying colors, text decorations, and formatting to terminal output.
4
+
5
+ ## Features
6
+
7
+ - **Rich Color Support**: Foreground and background colors with support for standard colors and hex values
8
+ - **Text Effects**: Bold, faint, italic, underline (including double), overline, blink, inverse, and concealed text
9
+ - **Style Composition**: Combine multiple styles using the `>>` operator for layered styling
10
+ - **Type Safety**: Comprehensive argument validation using dry-schema and dry-types
11
+ - **Immutable Design**: All style operations return new instances, making them safe for concurrent use
12
+ - **Zeitwerk Integration**: Automatic loading with proper module organization
13
+ - **Comprehensive API**: Both explicit `Style.new` and convenient `TIntMe[]` shortcut syntax
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem "tint_me"
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ ```bash
26
+ bundle install
27
+ ```
28
+
29
+ Or install it yourself as:
30
+
31
+ ```bash
32
+ gem install tint_me
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ### Basic Styling
38
+
39
+ ```ruby
40
+ require 'tint_me'
41
+
42
+ # Create a style
43
+ red_style = TIntMe::Style.new(foreground: :red)
44
+ puts red_style.call("Hello World")
45
+
46
+ # Using the shortcut syntax
47
+ blue_style = TIntMe[foreground: :blue, bold: true]
48
+ puts blue_style["Hello World"]
49
+ ```
50
+
51
+ ### Color Options
52
+
53
+ ```ruby
54
+ # Standard colors
55
+ TIntMe[foreground: :red]
56
+ TIntMe[background: :yellow]
57
+
58
+ # Hex colors (with or without #)
59
+ TIntMe[foreground: "#FF0000"]
60
+ TIntMe[background: "#00FF00"]
61
+ TIntMe[foreground: "FF0000"]
62
+ ```
63
+
64
+ ### Text Effects
65
+
66
+ ```ruby
67
+ # Individual effects
68
+ TIntMe[bold: true]
69
+ TIntMe[faint: true] # Faint/dim text
70
+ TIntMe[italic: true]
71
+ TIntMe[underline: true]
72
+ TIntMe[underline: :double] # Double underline
73
+ TIntMe[overline: true] # Overline decoration
74
+ TIntMe[blink: true] # Blinking text
75
+ TIntMe[inverse: true] # Reverse colors
76
+ TIntMe[conceal: true] # Hidden/concealed text
77
+
78
+ # Multiple effects
79
+ TIntMe[foreground: :green, bold: true, underline: true]
80
+ ```
81
+
82
+ ### Style Composition
83
+
84
+ ```ruby
85
+ # Base styling
86
+ base = TIntMe[foreground: :blue]
87
+ emphasis = TIntMe[bold: true, underline: true]
88
+
89
+ # Combine styles (right-hand style takes precedence)
90
+ combined = base >> emphasis
91
+ puts combined.call("Styled text")
92
+
93
+ # Chain multiple compositions
94
+ final = base >> emphasis >> TIntMe[background: :white]
95
+ ```
96
+
97
+ #### ⚡ Performance Considerations
98
+
99
+ **TIntMe is optimized for reusable styles** through SGR sequence pre-computation. The composition operator (`>>`) should be used thoughtfully:
100
+
101
+ ```ruby
102
+ # ✅ RECOMMENDED: Pre-compose and reuse
103
+ ERROR_STYLE = TIntMe[foreground: :red] >> TIntMe[bold: true]
104
+ ERROR_STYLE.call("Error message") # Fast: ~4.8M operations/sec
105
+
106
+ # ❌ AVOID: Runtime composition
107
+ (TIntMe[foreground: :red] >> TIntMe[bold: true]).call("Error") # Slow: ~0.01M ops/sec
108
+ ```
109
+
110
+ **Key Guidelines:**
111
+ - **Use `>>` for initialization**: Create composed styles once and reuse them
112
+ - **Avoid runtime composition**: Don't chain `>>` operators inside loops or frequently-called methods
113
+ - **For one-time styling**: Consider alternatives like `Paint` gem for better dynamic performance
114
+ - **Each `>>` operation**: Creates new Style instances and recalculates SGR sequences
115
+
116
+ **Performance Comparison:**
117
+ - Pre-computed styles: **~4.8M operations/sec** (fastest)
118
+ - Runtime composition: **~0.01M operations/sec** (246x slower)
119
+ - Direct Style.new: **~0.03M operations/sec** (71x slower)
120
+
121
+ #### 🎯 When to Use TIntMe vs Alternatives
122
+
123
+ **TIntMe excels at:**
124
+ ```ruby
125
+ # Terminal UI frameworks with predefined styles
126
+ UI_STYLES = {
127
+ error: TIntMe[foreground: :red] >> TIntMe[bold: true],
128
+ success: TIntMe[foreground: :green] >> TIntMe[bold: true],
129
+ info: TIntMe[foreground: :blue] >> TIntMe[italic: true]
130
+ }
131
+
132
+ def show_error(msg)
133
+ puts UI_STYLES[:error].call(msg) # Extremely fast: ~4.8M ops/sec
134
+ end
135
+ ```
136
+
137
+ **Consider alternatives for:**
138
+ ```ruby
139
+ # Dynamic styling (use Paint gem instead)
140
+ texts.each { |text| Paint[text, :red, :bold] } # ~2M ops/sec
141
+
142
+ # One-time styling with readable syntax (use Rainbow gem)
143
+ puts Rainbow("Success").green.bold # ~0.5M ops/sec
144
+
145
+ # Avoid with TIntMe - creates unnecessary overhead
146
+ texts.each { |text| (red >> bold).call(text) } # Only ~0.01M ops/sec
147
+ ```
148
+
149
+ **Design Philosophy:**
150
+ TIntMe is intentionally optimized for the **"define once, use many"** pattern through SGR sequence pre-computation at initialization time. The performance characteristics guide you toward the most efficient usage patterns, where a small set of predefined styles serves many styling operations.
151
+
152
+ ### Method Aliases
153
+
154
+ ```ruby
155
+ style = TIntMe[foreground: :red, bold: true]
156
+
157
+ # All of these are equivalent
158
+ puts style.call("Hello")
159
+ puts style["Hello"]
160
+ puts style.("Hello") # Callable syntax
161
+ ```
162
+
163
+ ## Development
164
+
165
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
166
+
167
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
168
+
169
+ ## Contributing
170
+
171
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sakuro/tint_me.
172
+
173
+ ## License
174
+
175
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/RELEASING.md ADDED
@@ -0,0 +1,202 @@
1
+ # Releasing
2
+
3
+ This document describes the release process for the tint_me gem, which is fully automated through GitHub Actions workflows.
4
+
5
+ ## Overview
6
+
7
+ The release process consists of three automated workflows:
8
+
9
+ 1. **Release Preparation** - Creates a release branch with version updates
10
+ 2. **Release Validation** - Validates the release branch on PR creation
11
+ 3. **Release Publish** - Publishes the gem after PR merge
12
+
13
+ ## Prerequisites
14
+
15
+ Before initiating a release, ensure:
16
+
17
+ - [ ] All desired features and fixes are merged to `main`
18
+ - [ ] CI is passing on `main` branch
19
+ - [ ] `CHANGELOG.md` has entries under `## [Unreleased]` section
20
+ - [ ] `RUBYGEMS_API_KEY` secret is configured in repository settings
21
+
22
+ ## Release Process
23
+
24
+ ### Step 1: Initiate Release
25
+
26
+ 1. Go to the [Actions tab](../../actions) in the GitHub repository
27
+ 2. Select "Release Preparation" workflow
28
+ 3. Click "Run workflow"
29
+ 4. Enter the version number (e.g., `1.0.0`)
30
+ 5. Click "Run workflow"
31
+
32
+ The workflow will automatically:
33
+ - Create a new branch `release-v{version}`
34
+ - Update `lib/tint_me/version.rb` with the new version
35
+ - Update `CHANGELOG.md`:
36
+ - Replace `## [Unreleased]` with `## [{version}] - {date}`
37
+ - Add a new `## [Unreleased]` section for future changes
38
+ - Create a git tag `v{version}` on the release branch
39
+ - Push the branch and tag to GitHub
40
+ - Create a Pull Request to `main`
41
+
42
+ ### Step 2: Review and Merge
43
+
44
+ Once the PR is created, the Release Validation workflow automatically:
45
+ - Validates version format (must be `x.y.z`)
46
+ - Verifies version consistency between branch name and `version.rb`
47
+ - Checks that the git tag doesn't already exist (or can be updated)
48
+ - Confirms the version isn't already published on RubyGems
49
+ - Verifies `RUBYGEMS_API_KEY` secret is configured
50
+ - Validates `CHANGELOG.md` has an entry for this version
51
+
52
+ **Note**: Quality checks (tests and RuboCop) are handled by the CI workflow to avoid duplication.
53
+
54
+ **Important**: If you push additional commits to the release PR (e.g., bug fixes, workflow updates, documentation changes):
55
+ - The validation workflow automatically moves the release tag to the latest commit
56
+ - This ensures the tag always points to the final reviewed code
57
+ - No manual intervention required
58
+ - All changes will be included in the final release
59
+
60
+ If all checks pass, merge the PR.
61
+
62
+ ### Step 3: Automatic Publishing
63
+
64
+ After the PR is merged, the Release Publish workflow automatically:
65
+ - Checks out the exact git tag created on the release branch
66
+ - Builds the gem from the tagged commit
67
+ - Publishes the gem to RubyGems
68
+ - Creates a GitHub Release with:
69
+ - Release notes extracted from `CHANGELOG.md`
70
+ - The built gem file as an attachment
71
+ - Cleans up the release branch
72
+
73
+ ## Workflow Architecture
74
+
75
+ ### Key Design Decisions
76
+
77
+ #### Tag-Based Deployment
78
+
79
+ The release workflow uses a **tag-based deployment strategy** to ensure the released gem contains exactly the code that was reviewed and approved in the release PR, without any subsequent changes from `main`.
80
+
81
+ ```mermaid
82
+ graph LR
83
+ A[main branch] -->|Create release branch| B[release-v1.0.0]
84
+ B -->|Update version & tag| C[Tagged: v1.0.0]
85
+ B -->|Create PR| D[Pull Request]
86
+ A -->|Other PRs merged| E[main with new commits]
87
+ D -->|Merge PR| E
88
+ C -->|Checkout tag| F[Build & Publish gem]
89
+ F -->|Contains only| G[Code from release branch]
90
+ ```
91
+
92
+ #### Automatic Tag Movement
93
+
94
+ When additional commits are pushed to a release PR, the tag automatically moves to the latest commit:
95
+
96
+ ```mermaid
97
+ graph LR
98
+ A[Initial commit] -->|Tag v1.0.0| B[Tagged commit]
99
+ B -->|Fix typo| C[New commit]
100
+ C -->|Auto-move tag| D[Tag v1.0.0 on latest]
101
+ D -->|Final review| E[Ready to merge]
102
+ ```
103
+
104
+ This ensures:
105
+ - The tag always points to the final reviewed code
106
+ - No manual tag management required
107
+ - The published gem matches exactly what was approved
108
+
109
+ ## Manual Release (Emergency Only)
110
+
111
+ If automation fails, you can release manually using our tag-based strategy:
112
+
113
+ ```bash
114
+ # 1. Create release branch
115
+ git checkout -b release-v1.0.0
116
+
117
+ # 2. Update version
118
+ vim lib/tint_me/version.rb
119
+
120
+ # 3. Update CHANGELOG (move content from [Unreleased] to [1.0.0])
121
+ vim CHANGELOG.md
122
+
123
+ # 4. Commit changes and create tag
124
+ git add -A
125
+ git commit -m ":bookmark: Release v1.0.0"
126
+ git tag -a v1.0.0 -m "Release v1.0.0"
127
+
128
+ # 5. Push release branch and tag
129
+ git push origin release-v1.0.0
130
+ git push origin v1.0.0
131
+
132
+ # 6. Create PR and merge after review
133
+ gh pr create --title "Release v1.0.0" --body "Release v1.0.0"
134
+ # (Review and merge PR)
135
+
136
+ # 7. Checkout the tag and build gem
137
+ git checkout v1.0.0
138
+ bundle exec rake build
139
+
140
+ # 8. Push to RubyGems
141
+ gem push pkg/tint_me-1.0.0.gem
142
+
143
+ # 9. Create GitHub release
144
+ gh release create v1.0.0 --title "tint_me v1.0.0" --generate-notes pkg/tint_me-1.0.0.gem
145
+ ```
146
+
147
+ ## Troubleshooting
148
+
149
+ ### Release Validation Fails
150
+
151
+ **Version already exists on RubyGems**
152
+ - Solution: Increment the version number and try again
153
+
154
+ **RUBYGEMS_API_KEY not configured**
155
+ 1. Generate an API key at https://rubygems.org/profile/edit
156
+ 2. Go to repository Settings → Secrets and variables → Actions
157
+ 3. Add new secret: `RUBYGEMS_API_KEY` with your API key
158
+
159
+ **Tests or RuboCop failing**
160
+ - These are checked by the CI workflow, not in release validation
161
+ - Fix the issues on the release branch or `main` as appropriate
162
+ - Release validation focuses on version consistency and format
163
+
164
+ ### Release Publish Fails
165
+
166
+ **Tag not found**
167
+ - The release preparation workflow may have failed to create the tag
168
+ - Check if the tag exists: `git tag | grep v1.0.0`
169
+ - If missing, the release validation workflow will recreate it on PR updates
170
+ - For manual fix: create tag on release branch with `git tag -a v1.0.0 -m "Release v1.0.0"`
171
+
172
+ **Gem push fails**
173
+ - Verify RubyGems API key is valid
174
+ - Check if you have push permissions for the gem
175
+ - Ensure the version doesn't already exist on RubyGems
176
+
177
+ ## Version Numbering
178
+
179
+ Follow [Semantic Versioning](https://semver.org/):
180
+
181
+ - **MAJOR** version for incompatible API changes
182
+ - **MINOR** version for backwards-compatible functionality additions
183
+ - **PATCH** version for backwards-compatible bug fixes
184
+
185
+ Examples:
186
+ - `0.1.0` → `0.1.1`: Bug fixes only
187
+ - `0.1.1` → `0.2.0`: New features added
188
+ - `0.2.0` → `1.0.0`: Breaking changes or stable release
189
+
190
+ ## Workflow Files
191
+
192
+ The release automation is implemented in:
193
+
194
+ - `.github/workflows/release-preparation.yml` - Creates release branch and PR
195
+ - `.github/workflows/release-validation.yml` - Validates release PR
196
+ - `.github/workflows/release-publish.yml` - Publishes gem after merge
197
+
198
+ ## Security Notes
199
+
200
+ - The `RUBYGEMS_API_KEY` secret is only accessible to workflows running on the default branch
201
+ - Release branches are automatically deleted after successful release
202
+ - All releases are tagged for audit trail and rollback capability
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ require "rspec/core/rake_task"
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+ RuboCop::RakeTask.new
10
+
11
+ require "yard"
12
+ YARD::Rake::YardocTask.new(:doc)
13
+
14
+ require "rake/clean"
15
+ CLEAN.include("coverage", ".yardoc", "docs/api", ".rspec_status")
16
+ CLOBBER.include("pkg")
17
+
18
+ task default: %i[spec rubocop]
@@ -0,0 +1,39 @@
1
+ BASELINE BENCHMARK RESULTS (Before Optimization)
2
+ =================================================
3
+ Date: 2025-09-08
4
+
5
+ ## Performance Summary
6
+
7
+ ### Style Application (operations/second)
8
+ - Simple style: ~766k ops/s (1.3μs per call)
9
+ - Complex style: ~437k ops/s (2.3μs per call)
10
+ - Hex color style: ~266k ops/s (3.8μs per call)
11
+
12
+ ### Repeated Application (1000x)
13
+ - Simple style: 781 ops/s (1.28ms total)
14
+ - Complex style: 433 ops/s (2.31ms total)
15
+ - Hex style: 265 ops/s (3.78ms total)
16
+
17
+ ### Memory Usage
18
+ - Simple style creation: 5.8KB, 52 objects
19
+ - Complex style creation: 6.6KB, 66 objects
20
+ - Simple style application (first): 45KB, 466 objects
21
+ - Complex style application (subsequent): 1.1KB, 14 objects
22
+
23
+ ### Object Allocations (100 applications)
24
+ - Simple style: 703 objects
25
+ - Complex style: 1203 objects
26
+
27
+ ## Key Observations
28
+
29
+ 1. **Performance overhead**: Each call recalculates SGR sequences
30
+ 2. **Object allocations**: Significant allocations on every call
31
+ 3. **Hex colors slower**: RGB conversion adds ~45% overhead
32
+ 4. **Complex styles slower**: More parameters = more processing
33
+
34
+ ## Expected Improvements with Caching
35
+
36
+ - Reduced object allocations per call
37
+ - Consistent performance regardless of style complexity
38
+ - Minimal overhead for repeated applications
39
+ - Trade-off: Slightly higher memory per Style instance