├── .editorconfig ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── BUG_REPORT.md │ ├── FEATURE_REQUEST.md │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── ci.yml ├── .gitignore ├── .rspec ├── .rubocop.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── appveyor.yml ├── bin ├── console └── setup ├── lib ├── tty-color.rb └── tty │ ├── color.rb │ └── color │ ├── mode.rb │ ├── support.rb │ └── version.rb ├── spec ├── spec_helper.rb └── unit │ ├── color_spec.rb │ ├── mode_spec.rb │ └── support_spec.rb ├── tasks ├── console.rake ├── coverage.rake └── spec.rake └── tty-color.gemspec /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.rb] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: piotrmurach 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG_REPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report something not working correctly or as expected 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | --- 8 | 9 | ### Describe the problem 10 | 11 | A brief description of the issue. 12 | 13 | ### Steps to reproduce the problem 14 | 15 | ``` 16 | Your code here to reproduce the issue 17 | ``` 18 | 19 | ### Actual behaviour 20 | 21 | What happened? This could be a description, log output, error raised etc. 22 | 23 | ### Expected behaviour 24 | 25 | What did you expect to happen? 26 | 27 | ### Describe your environment 28 | 29 | * OS version: 30 | * Ruby version: 31 | * TTY::Color version: 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest new functionality 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | --- 8 | 9 | ### Describe the problem 10 | 11 | A brief description of the problem you're trying to solve. 12 | 13 | ### How would the new feature work? 14 | 15 | A short explanation of the new feature. 16 | 17 | ``` 18 | Example code that shows possible usage 19 | ``` 20 | 21 | ### Drawbacks 22 | 23 | Can you see any potential drawbacks? 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: TTY Community Discussions 4 | url: https://github.com/piotrmurach/tty/discussions 5 | about: Suggest ideas, ask and answer questions 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Describe the change 2 | What does this Pull Request do? 3 | 4 | ### Why are we doing this? 5 | Any related context as to why is this is a desirable change. 6 | 7 | ### Benefits 8 | How will the library improve? 9 | 10 | ### Drawbacks 11 | Possible drawbacks applying this change. 12 | 13 | ### Requirements 14 | 15 | - [ ] Tests written & passing locally? 16 | - [ ] Code style checked? 17 | - [ ] Rebased with `master` branch? 18 | - [ ] Documentation updated? 19 | - [ ] Changelog updated? 20 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: CI 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths-ignore: 8 | - "bin/**" 9 | - "*.md" 10 | pull_request: 11 | branches: 12 | - master 13 | paths-ignore: 14 | - "bin/**" 15 | - "*.md" 16 | jobs: 17 | tests: 18 | name: Ruby ${{ matrix.ruby }} 19 | runs-on: ${{ matrix.os || 'ubuntu-latest' }} 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | ruby: 24 | - "2.0" 25 | - "2.1" 26 | - "2.2" 27 | - "2.3" 28 | - "2.4" 29 | - "2.5" 30 | - "2.6" 31 | - "3.0" 32 | - "3.1" 33 | - "3.2" 34 | - "3.3" 35 | - "3.4" 36 | - ruby-head 37 | - jruby-9.3 38 | - jruby-9.4 39 | - jruby-10.0 40 | - jruby-head 41 | - truffleruby-head 42 | include: 43 | - ruby: "2.7" 44 | coverage: true 45 | - ruby: jruby-9.2 46 | os: ubuntu-22.04 47 | env: 48 | COVERAGE: ${{ matrix.coverage }} 49 | COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} 50 | continue-on-error: ${{ endsWith(matrix.ruby, 'head') }} 51 | steps: 52 | - uses: actions/checkout@v4 53 | - name: Set up Ruby 54 | uses: ruby/setup-ruby@v1 55 | with: 56 | ruby-version: ${{ matrix.ruby }} 57 | bundler-cache: true 58 | - name: Run tests 59 | run: bundle exec rake ci 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | *.bundle 11 | *.so 12 | *.o 13 | *.a 14 | mkmf.log 15 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | --warnings 4 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | NewCops: enable 3 | 4 | Lint/AssignmentInCondition: 5 | Enabled: false 6 | 7 | Metrics/AbcSize: 8 | Max: 30 9 | 10 | Metrics/BlockLength: 11 | CountComments: true 12 | Max: 25 13 | ExcludedMethods: [] 14 | Exclude: 15 | - "spec/**/*" 16 | 17 | Metrics/ClassLength: 18 | Max: 1500 19 | 20 | Metrics/CyclomaticComplexity: 21 | Enabled: false 22 | 23 | Metrics/LineLength: 24 | Max: 80 25 | 26 | Metrics/MethodLength: 27 | Max: 20 28 | 29 | Naming/BinaryOperatorParameterName: 30 | Enabled: false 31 | 32 | Style/AsciiComments: 33 | Enabled: false 34 | 35 | Style/LambdaCall: 36 | SupportedStyles: 37 | - call 38 | - braces 39 | 40 | Style/StringLiterals: 41 | EnforcedStyle: double_quotes 42 | 43 | Style/TrivialAccessors: 44 | Enabled: false 45 | 46 | # { ... } for multi-line blocks is okay 47 | Style/BlockDelimiters: 48 | Enabled: false 49 | 50 | Style/CommentedKeyword: 51 | Enabled: false 52 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change log 2 | 3 | ## [v0.6.0] - 2020-11-07 4 | 5 | ### Added 6 | * Add 24bit color aka "direct color" aka "truecolor" by @nevans 7 | * Add support for NO_COLOR env var by @nevans 8 | 9 | ### Changed 10 | * Change to freeze all regular expressions 11 | * Change to increase test coverage to 100% 12 | 13 | ## [v0.5.2] - 2020-08-09 14 | 15 | ### Changed 16 | * Change gemspec and remove bundler as dev dependency 17 | * Change TTY::Color::Support to define verbose as keyword argument 18 | 19 | ### Fix 20 | * Fix gemspec metadata links by Igor Kapkov(@igas) 21 | 22 | ## [v0.5.1] - 2020-01-22 23 | 24 | ### Changed 25 | * Change gemspec to add metadata and remove test artefacts 26 | 27 | ## [v0.5.0] - 2019-05-29 28 | 29 | ### Changed 30 | * Change gemspec to load files without git 31 | * Change to limit to Ruby >= 2.0.0 32 | 33 | ## [v0.4.3] - 2018-07-11 34 | 35 | ### Changed 36 | * Change to use relative file paths 37 | * Change to ensure immutable strings 38 | * Change Color to use alias call 39 | 40 | ### Fixed 41 | * Fix to support iTerm 2.app for 256 color mode detection by Michael Lang(@mwlang) 42 | 43 | ## [v0.4.2] - 2017-02-06 44 | 45 | ### Fixed 46 | * Fix File namespaces 47 | 48 | ## [v0.4.1] - 2017-01-22 49 | 50 | ### Fixed 51 | * Fix #windows? to reference top level constant 52 | 53 | ## [v0.4.0] - 2016-12-27 54 | 55 | ### Added 56 | * Add #command? helper 57 | * Add #windows? helper 58 | 59 | ### Changed 60 | * Change to stop checking curses on Windows 61 | 62 | ### Fixed 63 | * Fix Support#from_tput check to fail gracefully on non-unix systems 64 | * Fix Mode#from_tput check to fail gracefuly on non-unix systems 65 | 66 | ## [v0.3.0] - 2016-01-13 67 | 68 | ### Fixed 69 | 70 | * Fix #tty? check 71 | 72 | ## [v0.2.0] - 2016-01-13 73 | 74 | ### Changed 75 | 76 | * Change ordering of color support checks by @janlelis 77 | * Change ordering of color mode 78 | * Change Support#from_env to check ansicon 79 | * Ensure #tty? works for non-terminal devices 80 | * Remove color executable 81 | 82 | ## [v0.1.0] - 2016-01-02 83 | 84 | * Initial implementation and release 85 | 86 | [v0.6.0]: https://github.com/piotrmurach/tty-color/compare/v0.5.2...v0.6.0 87 | [v0.5.2]: https://github.com/piotrmurach/tty-color/compare/v0.5.1...v0.5.2 88 | [v0.5.1]: https://github.com/piotrmurach/tty-color/compare/v0.5.0...v0.5.1 89 | [v0.5.0]: https://github.com/piotrmurach/tty-color/compare/v0.4.3...v0.5.0 90 | [v0.4.3]: https://github.com/piotrmurach/tty-color/compare/v0.4.2...v0.4.3 91 | [v0.4.2]: https://github.com/piotrmurach/tty-color/compare/v0.4.1...v0.4.2 92 | [v0.4.1]: https://github.com/piotrmurach/tty-color/compare/v0.4.0...v0.4.1 93 | [v0.4.0]: https://github.com/piotrmurach/tty-color/compare/v0.3.0...v0.4.0 94 | [v0.3.0]: https://github.com/piotrmurach/tty-color/compare/v0.2.0...v0.3.0 95 | [v0.2.0]: https://github.com/piotrmurach/tty-color/compare/v0.1.0...v0.2.0 96 | [v0.1.0]: https://github.com/piotrmurach/tty-color/compare/v0.1.0 97 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | piotr@piotrmurach.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations 133 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | gemspec 6 | 7 | gem "json", "2.4.1" if RUBY_VERSION == "2.0.0" 8 | gem "yardstick", "~> 0.9.9" 9 | 10 | if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7.0") 11 | gem "coveralls_reborn", "~> 0.28.0" 12 | gem "simplecov", "~> 0.22.0" 13 | end 14 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Piotr Murach (https://piotrmurach.com) 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | TTY Toolkit logo 3 |
4 | 5 | # TTY::Color 6 | 7 | [![Gem Version](https://badge.fury.io/rb/tty-color.svg)][gem] 8 | [![Actions CI](https://github.com/piotrmurach/tty-color/actions/workflows/ci.yml/badge.svg)][gh_actions_ci] 9 | [![Build status](https://ci.appveyor.com/api/projects/status/j1nflklmnfrb2yrf?svg=true)][appveyor] 10 | [![Code Climate](https://codeclimate.com/github/piotrmurach/tty-color/badges/gpa.svg)][codeclimate] 11 | [![Coverage Status](https://coveralls.io/repos/github/piotrmurach/tty-color/badge.svg)][coverage] 12 | 13 | [gem]: https://badge.fury.io/rb/tty-color 14 | [gh_actions_ci]: https://github.com/piotrmurach/tty-color/actions/workflows/ci.yml 15 | [appveyor]: https://ci.appveyor.com/project/piotrmurach/tty-color 16 | [codeclimate]: https://codeclimate.com/github/piotrmurach/tty-color 17 | [coverage]: https://coveralls.io/github/piotrmurach/tty-color 18 | 19 | > Terminal color capabilities detection. 20 | 21 | **TTY::Color** provides independent color support detection component for [TTY](https://github.com/piotrmurach/tty) toolkit. 22 | 23 | ## Installation 24 | 25 | Add this line to your application's Gemfile: 26 | 27 | ```ruby 28 | gem "tty-color" 29 | ``` 30 | 31 | And then execute: 32 | 33 | $ bundle 34 | 35 | Or install it yourself as: 36 | 37 | $ gem install tty-color 38 | 39 | ## Usage 40 | 41 | **TTY::Color** allows you to check if terminal supports color: 42 | 43 | ```ruby 44 | TTY::Color.color? # => true 45 | TTY::Color.support? # => true 46 | ``` 47 | 48 | You can also get the number of colors supported by the terminal using `mode` method: 49 | 50 | ```ruby 51 | TTY::Color.mode # => 64 52 | ``` 53 | 54 | To detect if color support has been disabled with `NO_COLOR` environment variable, use `disabled?`: 55 | 56 | ```ruby 57 | TTY::Color.disabled? # => false 58 | ``` 59 | 60 | **TTY::Color** is just a module hence you can include it into your scripts directly: 61 | 62 | ```ruby 63 | #!/usr/bin/env ruby 64 | 65 | include TTY::Color 66 | 67 | puts color? 68 | ``` 69 | 70 | ## Command line tool 71 | 72 | [tty-color-cli](https://github.com/piotrmurach/tty-color-cli) is a command line tool for the **TTY::Color**. 73 | 74 | To check if terminal supports colors use `-s|--support`: 75 | 76 | ```bash 77 | tty-color -s 78 | tty-color --support 79 | # => true 80 | ``` 81 | 82 | And to check color mode use `-m|--mode` option: 83 | 84 | ```bash 85 | tty-color -m 86 | tty-color --mode 87 | # => 256 88 | ``` 89 | 90 | ## Development 91 | 92 | 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. 93 | 94 | 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 tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 95 | 96 | ## Contributing 97 | 98 | Bug reports and pull requests are welcome on GitHub at https://github.com/piotrmurach/tty-color. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. 99 | 100 | 1. Fork it ( https://github.com/piotrmurach/tty-color/fork ) 101 | 2. Create your feature branch (`git checkout -b my-new-feature`) 102 | 3. Commit your changes (`git commit -am 'Add some feature'`) 103 | 4. Push to the branch (`git push origin my-new-feature`) 104 | 5. Create a new Pull Request 105 | 106 | ## Code of Conduct 107 | 108 | Everyone interacting in the TTY::Color project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/piotrmurach/tty-color/blob/master/CODE_OF_CONDUCT.md). 109 | 110 | ## Copyright 111 | 112 | Copyright (c) 2016 Piotr Murach. See LICENSE for further details. 113 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "bundler/gem_tasks" 4 | 5 | FileList["tasks/**/*.rake"].each(&method(:import)) 6 | 7 | desc "Run all specs" 8 | task ci: %w[ spec ] 9 | 10 | task default: :spec 11 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | --- 2 | skip_commits: 3 | files: 4 | - "bin/**" 5 | - "*.md" 6 | install: 7 | - SET PATH=C:\Ruby%ruby_version%\bin;%PATH% 8 | - gem install bundler -v '< 2.0' 9 | - bundle install 10 | before_test: 11 | - ruby -v 12 | - gem -v 13 | - bundle -v 14 | build: off 15 | test_script: 16 | - bundle exec rake ci 17 | environment: 18 | matrix: 19 | - ruby_version: "200" 20 | - ruby_version: "200-x64" 21 | - ruby_version: "21" 22 | - ruby_version: "21-x64" 23 | - ruby_version: "22" 24 | - ruby_version: "22-x64" 25 | - ruby_version: "23" 26 | - ruby_version: "23-x64" 27 | - ruby_version: "24" 28 | - ruby_version: "24-x64" 29 | - ruby_version: "25" 30 | - ruby_version: "25-x64" 31 | - ruby_version: "26" 32 | - ruby_version: "26-x64" 33 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "tty/color" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start(__FILE__) 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /lib/tty-color.rb: -------------------------------------------------------------------------------- 1 | require_relative "tty/color" 2 | -------------------------------------------------------------------------------- /lib/tty/color.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "color/mode" 4 | require_relative "color/support" 5 | require_relative "color/version" 6 | 7 | module TTY 8 | # Responsible for checking terminal color support 9 | # 10 | # @api public 11 | module Color 12 | extend self 13 | 14 | NoValue = Module.new 15 | 16 | @verbose = false 17 | 18 | @output = $stderr 19 | 20 | attr_accessor :output, :verbose 21 | 22 | # Check if terminal supports colors 23 | # 24 | # @return [Boolean] 25 | # 26 | # @api public 27 | def support? 28 | Support.new(ENV, verbose: verbose).support? 29 | end 30 | alias supports? support? 31 | alias color? support? 32 | alias supports_color? support? 33 | 34 | # Detect if color support has been disabled with NO_COLOR ENV var. 35 | # 36 | # @return [Boolean] 37 | # true when terminal color support has been disabled, false otherwise 38 | # 39 | # @api public 40 | def disabled? 41 | Support.new(ENV, verbose: verbose).disabled? 42 | end 43 | 44 | # Check how many colors this terminal supports 45 | # 46 | # @return [Integer] 47 | # 48 | # @api public 49 | def mode 50 | Mode.new(ENV).mode 51 | end 52 | 53 | # Check if output is linked with terminal 54 | # 55 | # @return [Boolean] 56 | # 57 | # @api public 58 | def tty? 59 | output.respond_to?(:tty?) && output.tty? 60 | end 61 | 62 | # Check if command can be run 63 | # 64 | # @return [Boolean] 65 | # 66 | # @api public 67 | def command?(cmd) 68 | !!system(cmd, out: ::File::NULL, err: ::File::NULL) 69 | end 70 | 71 | # Check if Windowz 72 | # 73 | # @return [Boolean] 74 | # 75 | # @api public 76 | def windows? 77 | ::File::ALT_SEPARATOR == "\\" 78 | end 79 | end # Color 80 | end # TTY 81 | -------------------------------------------------------------------------------- /lib/tty/color/mode.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module TTY 4 | module Color 5 | class Mode 6 | TERM_24BIT = /[+-]direct/.freeze 7 | TRUECOLORS = 2**24 # 8 bits per RGB channel 8 | 9 | TERM_256 = /^(alacritty|iTerm\s?\d*\.app|kitty|mintty|ms-terminal| 10 | nsterm|nsterm-build\d+|terminator|terminology(-[0-9.]+)?| 11 | termite|vscode)$/x.freeze 12 | 13 | TERM_64 = /^(hpterm-color|wy370|wy370-105k|wy370-EPC|wy370-nk| 14 | wy370-rv|wy370-tek|wy370-vb|wy370-w|wy370-wvb)$/x.freeze 15 | 16 | TERM_52 = /^(dg+ccc|dgunix+ccc|d430.*?[-+](dg|unix).*?[-+]ccc)$/x.freeze 17 | 18 | TERM_16 = /^(amiga-vnc|d430-dg|d430-unix|d430-unix-25|d430-unix-s| 19 | d430-unix-sr|d430-unix-w|d430c-dg|d430c-unix|d430c-unix-25| 20 | d430c-unix-s|d430c-unix-sr|d430c-unix-w|d470|d470-7b|d470-dg| 21 | d470c|d470c-7b|d470c-dg|dg+color|dg\+fixed|dgunix\+fixed| 22 | dgmode\+color|hp\+color|ncr260wy325pp|ncr260wy325wpp| 23 | ncr260wy350pp|ncr260wy350wpp|nsterm-c|nsterm-c-acs| 24 | nsterm-c-s|nsterm-c-s-7|nsterm-c-s-acs|nsterm\+c| 25 | nsterm-7-c|nsterm-bce)$/x.freeze 26 | 27 | TERM_8 = /vt100|xnuppc|wy350/x.freeze 28 | 29 | METHODS = %w[from_term from_tput].freeze 30 | 31 | def initialize(env) 32 | @env = env 33 | end 34 | 35 | # Detect supported colors 36 | # 37 | # @return [Integer] 38 | # out of 0, 8, 16, 52, 66, 256, 2^24 39 | # 40 | # @api public 41 | def mode 42 | return 0 unless TTY::Color.tty? 43 | 44 | value = 8 45 | METHODS.each do |from_check| 46 | break if (value = public_send(from_check)) != NoValue 47 | end 48 | return 8 if value == NoValue 49 | value 50 | end 51 | 52 | # Check TERM environment for colors 53 | # 54 | # @return [NoValue, Integer] 55 | # 56 | # @api private 57 | def from_term 58 | case @env["TERM"] 59 | when TERM_24BIT then TRUECOLORS 60 | when /[-+](\d+)color/ then $1.to_i 61 | when /[-+](\d+)bit/ then 2**$1.to_i 62 | when TERM_256 then 256 63 | when TERM_64 then 64 64 | when TERM_52 then 52 65 | when TERM_16 then 16 66 | when TERM_8 then 8 67 | when /dummy/ then 0 68 | else NoValue 69 | end 70 | end 71 | 72 | # Shell out to tput to check color support 73 | # 74 | # @return [NoValue, Integer] 75 | # 76 | # @api private 77 | def from_tput 78 | return NoValue unless TTY::Color.command?("tput colors") 79 | 80 | colors = `tput colors 2>/dev/null`.to_i 81 | colors >= 8 ? colors : NoValue 82 | rescue Errno::ENOENT 83 | NoValue 84 | end 85 | end # Mode 86 | end # Color 87 | end # TTY 88 | -------------------------------------------------------------------------------- /lib/tty/color/support.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module TTY 4 | module Color 5 | class Support 6 | SOURCES = %w[from_term from_tput from_env from_curses].freeze 7 | ENV_VARS = %w[COLORTERM ANSICON].freeze 8 | 9 | TERM_REGEX = / 10 | color| # explicitly claims color support in the name 11 | direct| # explicitly claims "direct color" (24 bit) support 12 | 13 | #{Mode::TERM_256}| 14 | #{Mode::TERM_64}| 15 | #{Mode::TERM_52}| 16 | #{Mode::TERM_16}| 17 | #{Mode::TERM_8}| 18 | 19 | ^ansi(\.sys.*)?$| 20 | ^cygwin| 21 | ^linux| 22 | ^putty| 23 | ^rxvt| 24 | ^screen| 25 | ^tmux| 26 | ^xterm/xi.freeze 27 | 28 | # Initialize a color support 29 | # @api public 30 | def initialize(env, verbose: false) 31 | @env = env 32 | @verbose = verbose 33 | end 34 | 35 | # Detect if terminal supports color 36 | # 37 | # @return [Boolean] 38 | # true when terminal supports color, false otherwise 39 | # 40 | # @api public 41 | def support? 42 | return false unless TTY::Color.tty? 43 | return false if disabled? 44 | 45 | value = false 46 | SOURCES.each do |from_check| 47 | break if (value = public_send(from_check)) != NoValue 48 | end 49 | value == NoValue ? false : value 50 | end 51 | 52 | # Detect if color support has been disabled with NO_COLOR ENV var. 53 | # 54 | # @return [Boolean] 55 | # true when terminal color support has been disabled, false otherwise 56 | # 57 | # @api public 58 | def disabled? 59 | no_color = @env["NO_COLOR"] 60 | !(no_color.nil? || no_color.empty?) 61 | end 62 | 63 | # Inspect environment $TERM variable for color support 64 | # 65 | # @api private 66 | def from_term 67 | case @env["TERM"] 68 | when "dumb" then false 69 | when TERM_REGEX then true 70 | else NoValue 71 | end 72 | end 73 | 74 | # Shell out to tput to check color support 75 | # 76 | # @api private 77 | def from_tput 78 | return NoValue unless TTY::Color.command?("tput colors") 79 | 80 | `tput colors 2>/dev/null`.to_i > 2 81 | rescue Errno::ENOENT 82 | NoValue 83 | end 84 | 85 | # Check if environment specifies color variables 86 | # 87 | # @api private 88 | def from_env 89 | ENV_VARS.any? { |key| @env.key?(key) } || NoValue 90 | end 91 | 92 | # Attempt to load curses to check color support 93 | # 94 | # @return [Boolean] 95 | # 96 | # @api private 97 | def from_curses(curses_class = nil) 98 | return NoValue if TTY::Color.windows? 99 | 100 | require "curses" 101 | 102 | if defined?(Curses) 103 | curses_class ||= Curses 104 | curses_class.init_screen 105 | has_color = curses_class.has_colors? 106 | curses_class.close_screen 107 | return has_color 108 | end 109 | NoValue 110 | rescue LoadError 111 | warn "no native curses support" if @verbose 112 | NoValue 113 | end 114 | end # Support 115 | end # Color 116 | end # TTY 117 | -------------------------------------------------------------------------------- /lib/tty/color/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module TTY 4 | module Color 5 | VERSION = "0.6.0" 6 | end # Color 7 | end # TTY 8 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | if ENV["COVERAGE"] == "true" 4 | require "simplecov" 5 | require "coveralls" 6 | 7 | SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([ 8 | SimpleCov::Formatter::HTMLFormatter, 9 | Coveralls::SimpleCov::Formatter 10 | ]) 11 | 12 | SimpleCov.start do 13 | command_name "spec" 14 | add_filter "spec" 15 | end 16 | end 17 | 18 | require "tty-color" 19 | 20 | RSpec.configure do |config| 21 | config.expect_with :rspec do |expectations| 22 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 23 | expectations.max_formatted_output_length = nil 24 | end 25 | 26 | config.mock_with :rspec do |mocks| 27 | mocks.verify_partial_doubles = true 28 | end 29 | 30 | # Limits the available syntax to the non-monkey patched syntax that is recommended. 31 | config.disable_monkey_patching! 32 | 33 | # This setting enables warnings. It's recommended, but in some cases may 34 | # be too noisy due to issues in dependencies. 35 | config.warnings = true 36 | 37 | if config.files_to_run.one? 38 | config.default_formatter = "doc" 39 | end 40 | 41 | config.profile_examples = 2 42 | 43 | config.order = :random 44 | 45 | Kernel.srand config.seed 46 | end 47 | -------------------------------------------------------------------------------- /spec/unit/color_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe TTY::Color, "integratation" do 4 | it "defaults output to stderr" do 5 | expect(TTY::Color.output).to eq($stderr) 6 | end 7 | 8 | it "defaults verbose mode to false" do 9 | expect(TTY::Color.verbose).to eq(false) 10 | end 11 | 12 | it "accesses color mode" do 13 | mode_instance = spy(:mode) 14 | allow(TTY::Color::Mode).to receive(:new).and_return(mode_instance) 15 | 16 | described_class.mode 17 | 18 | expect(mode_instance).to have_received(:mode) 19 | end 20 | 21 | it "accesses color support" do 22 | support_instance = spy(:support) 23 | allow(TTY::Color::Support).to receive(:new).and_return(support_instance) 24 | 25 | described_class.support? 26 | 27 | expect(support_instance).to have_received(:support?) 28 | end 29 | 30 | it "accesses disabled support" do 31 | support_instance = spy(:support, disabled?: :maybe) 32 | allow(TTY::Color::Support).to receive(:new).and_return(support_instance) 33 | 34 | expect(described_class.disabled?).to eq(:maybe) 35 | 36 | expect(support_instance).to have_received(:disabled?) 37 | end 38 | 39 | it "checks unknown command without raising errors and returns false" do 40 | allow(described_class).to receive(:system) 41 | .with("unknown-command", { out: ::File::NULL, err: ::File::NULL }) 42 | .and_return(nil) 43 | 44 | expect(described_class.command?("unknown-command")).to eq(false) 45 | end 46 | 47 | it "checks 'echo' command and returns true" do 48 | allow(described_class).to receive(:system). 49 | with("echo", { out: ::File::NULL, err: ::File::NULL }).and_return("") 50 | 51 | expect(described_class.command?("echo")).to eq(true) 52 | end 53 | 54 | it "detects windows platform" do 55 | stub_const("::File::ALT_SEPARATOR", "\\") 56 | 57 | expect(described_class.windows?).to eq(true) 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /spec/unit/mode_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe TTY::Color::Mode, "detecting mode" do 4 | it "isn't terminal" do 5 | allow(TTY::Color).to receive(:tty?).and_return(false) 6 | mode = described_class.new({}) 7 | expect(mode.mode).to eq(0) 8 | end 9 | 10 | it "cannot find from term, tput " do 11 | allow(TTY::Color).to receive(:tty?).and_return(true) 12 | mode = described_class.new({}) 13 | allow(mode).to receive(:from_term).and_return(TTY::Color::NoValue) 14 | allow(mode).to receive(:from_tput).and_return(TTY::Color::NoValue) 15 | 16 | expect(mode.mode).to eq(8) 17 | expect(mode).to have_received(:from_term).ordered 18 | expect(mode).to have_received(:from_tput).ordered 19 | end 20 | 21 | it "detects color mode" do 22 | allow(TTY::Color).to receive(:tty?).and_return(true) 23 | mode = described_class.new("TERM" => "xterm-256color") 24 | 25 | expect(mode.mode).to eq(256) 26 | end 27 | 28 | context "#from_term" do 29 | { 30 | "xterm+direct" => 16_777_216, 31 | "vscode-direct" => 16_777_216, 32 | "+24bit" => 16_777_216, 33 | "xterm-256color" => 256, 34 | "alacritty" => 256, 35 | "mintty" => 256, 36 | "ms-terminal" => 256, 37 | "nsterm" => 256, 38 | "nsterm-build400" => 256, 39 | "terminator" => 256, 40 | "vscode" => 256, 41 | "iTerm.app" => 256, 42 | "iTerm 2.app" => 256, 43 | "amiga-8bit" => 256, 44 | "+8bit" => 256, 45 | "wy370-105k" => 64, 46 | "d430-unix-ccc" => 52, 47 | "d430c-unix-s-ccc" => 52, 48 | "+52color" => 52, 49 | "nsterm-bce" => 16, 50 | "d430c-dg" => 16, 51 | "d430-unix-w" => 16, 52 | "konsole-vt100" => 8, 53 | "xnuppc+basic" => 8, 54 | "dummy" => 0 55 | }.each do |term_name, number| 56 | it "infers #{term_name.inspect} to have #{number} colors" do 57 | mode = described_class.new("TERM" => term_name) 58 | expect(mode.from_term).to eq(number) 59 | end 60 | end 61 | 62 | it "doesn't match any term variable" do 63 | mode = described_class.new({}) 64 | expect(mode.from_term).to eq(TTY::Color::NoValue) 65 | end 66 | end 67 | 68 | context "#from_tput" do 69 | it "fails to find tput utility" do 70 | mode = described_class.new({}) 71 | allow(TTY::Color).to receive(:command?).with("tput colors").and_return(nil) 72 | 73 | expect(mode.from_tput).to eq(TTY::Color::NoValue) 74 | end 75 | 76 | it "runs tput and detects 8 colors" do 77 | allow(TTY::Color).to receive(:command?).with("tput colors").and_return(true) 78 | mode = described_class.new({}) 79 | allow(mode).to receive(:`).and_return("8") 80 | 81 | expect(mode.from_tput).to eq(8) 82 | end 83 | 84 | it "runs tput but finds less than 8 colors" do 85 | allow(TTY::Color).to receive(:command?).with("tput colors").and_return(true) 86 | mode = described_class.new({}) 87 | allow(mode).to receive(:`).and_return("2") 88 | 89 | expect(mode.from_tput).to eq(TTY::Color::NoValue) 90 | end 91 | 92 | it "raises error when running tput" do 93 | allow(TTY::Color).to receive(:command?).with("tput colors").and_return(true) 94 | mode = described_class.new({}) 95 | allow(mode).to receive(:`).and_raise(Errno::ENOENT) 96 | 97 | expect(mode.from_tput).to eq(TTY::Color::NoValue) 98 | end 99 | end 100 | end 101 | -------------------------------------------------------------------------------- /spec/unit/support_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe TTY::Color::Support, "#support?" do 4 | it "doesn't check color support for non tty terminal" do 5 | support = described_class.new({}) 6 | allow(TTY::Color).to receive(:tty?).and_return(false) 7 | expect(support.support?).to eq(false) 8 | end 9 | 10 | it "disables color support when NO_COLOR is set" do 11 | support = described_class.new({"NO_COLOR" => "1"}) 12 | expect(support.support?).to eq(false) 13 | expect(support).to be_disabled 14 | end 15 | 16 | it "fails to find out color support" do 17 | support = described_class.new({}) 18 | allow(TTY::Color).to receive(:tty?).and_return(true) 19 | 20 | allow(support).to receive(:from_curses).and_return(TTY::Color::NoValue) 21 | allow(support).to receive(:from_tput).and_return(TTY::Color::NoValue) 22 | allow(support).to receive(:from_term).and_return(TTY::Color::NoValue) 23 | allow(support).to receive(:from_env).and_return(TTY::Color::NoValue) 24 | 25 | expect(support.support?).to eq(false) 26 | 27 | expect(support).to have_received(:from_term).ordered 28 | expect(support).to have_received(:from_tput).ordered 29 | expect(support).to have_received(:from_env).ordered 30 | expect(support).to have_received(:from_curses).ordered 31 | end 32 | 33 | it "detects color support" do 34 | support = described_class.new({"TERM" => "xterm"}) 35 | allow(TTY::Color).to receive(:tty?).and_return(true) 36 | allow(support).to receive(:from_tput) 37 | 38 | expect(support.support?).to eq(true) 39 | expect(support).to_not have_received(:from_tput) 40 | end 41 | 42 | context "#from_curses" do 43 | it "fails to load curses for color support" do 44 | support = described_class.new({}) 45 | allow(TTY::Color).to receive(:windows?).and_return(false) 46 | allow(support).to receive(:require).with("curses").and_raise(LoadError) 47 | allow(support).to receive(:warn) 48 | 49 | expect(support.from_curses).to eq(TTY::Color::NoValue) 50 | expect(support).to_not have_received(:warn) 51 | end 52 | 53 | it "fails to find Curses namespace" do 54 | support = described_class.new({}) 55 | allow(TTY::Color).to receive(:windows?).and_return(false) 56 | allow(support).to receive(:require).with("curses") 57 | 58 | expect(support.from_curses).to eq(TTY::Color::NoValue) 59 | end 60 | 61 | it "sets verbose mode on" do 62 | support = described_class.new({}, verbose: true) 63 | allow(TTY::Color).to receive(:windows?).and_return(false) 64 | allow(support).to receive(:require).with("curses").and_raise(LoadError) 65 | allow(support).to receive(:warn) 66 | 67 | support.from_curses 68 | 69 | expect(support).to have_received(:warn).with(/no native curses support/) 70 | end 71 | 72 | it "loads curses for color support" do 73 | support = described_class.new({}) 74 | allow(TTY::Color).to receive(:windows?).and_return(false) 75 | allow(support).to receive(:require).with("curses").and_return(true) 76 | stub_const("Curses", Object.new) 77 | curses = double(:curses) 78 | allow(curses).to receive(:init_screen) 79 | allow(curses).to receive(:has_colors?).and_return(true) 80 | allow(curses).to receive(:close_screen) 81 | 82 | expect(support.from_curses(curses)).to eql(true) 83 | expect(curses).to have_received(:has_colors?) 84 | end 85 | 86 | it "doesn't check on windows" do 87 | support = described_class.new({}) 88 | allow(TTY::Color).to receive(:windows?).and_return(true) 89 | expect(support.from_curses).to eq(TTY::Color::NoValue) 90 | end 91 | end 92 | 93 | context "#from_term" do 94 | it "fails to find color for dumb terminal" do 95 | support = described_class.new({"TERM" => "dumb"}) 96 | expect(support.from_term).to eq(false) 97 | end 98 | 99 | it "inspects term variable for color capabilities" do 100 | support = described_class.new({"TERM" => "xterm"}) 101 | expect(support.from_term).to eq(true) 102 | support = described_class.new({"TERM" => "tmux-256color"}) 103 | expect(support.from_term).to eq(true) 104 | end 105 | 106 | it "fails to find color capabilities from term variable " do 107 | support = described_class.new({"TERM" => "atari"}) 108 | expect(support.from_term).to eq(TTY::Color::NoValue) 109 | end 110 | end 111 | 112 | context "#from_tput" do 113 | it "fails to find tput utilty" do 114 | support = described_class.new({}) 115 | allow(TTY::Color).to receive(:command?).with("tput colors").and_return(nil) 116 | 117 | expect(support.from_tput).to eq(TTY::Color::NoValue) 118 | end 119 | 120 | it "runs tput and detects 8 colors" do 121 | allow(TTY::Color).to receive(:command?).with("tput colors").and_return(true) 122 | support = described_class.new({}) 123 | allow(support).to receive(:`).and_return("8") 124 | 125 | expect(support.from_tput).to eq(true) 126 | end 127 | 128 | it "runs tput but finds no colors" do 129 | allow(TTY::Color).to receive(:command?).with("tput colors").and_return(true) 130 | support = described_class.new({}) 131 | allow(support).to receive(:`).and_return("2") 132 | 133 | expect(support.from_tput).to eq(false) 134 | end 135 | 136 | it "raises error when running tput" do 137 | allow(TTY::Color).to receive(:command?).with("tput colors").and_return(true) 138 | support = described_class.new({}) 139 | allow(support).to receive(:`).and_raise(Errno::ENOENT) 140 | 141 | expect(support.from_tput).to eq(TTY::Color::NoValue) 142 | end 143 | end 144 | 145 | context "#from_env" do 146 | it "finds color support in colorterm variable" do 147 | support = described_class.new({"COLORTERM" => true}) 148 | expect(support.from_env).to eq(true) 149 | end 150 | 151 | it "finds ansicon support" do 152 | support = described_class.new({"ANSICON" => true}) 153 | expect(support.from_env).to eq(true) 154 | end 155 | 156 | it "doesn't find any keys in environment" do 157 | support = described_class.new({}) 158 | expect(support.from_env).to eq(TTY::Color::NoValue) 159 | end 160 | end 161 | end 162 | -------------------------------------------------------------------------------- /tasks/console.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | desc "Load gem inside irb console" 4 | task :console do 5 | require "irb" 6 | require "irb/completion" 7 | require File.join(__FILE__, "../../lib/tty-color") 8 | ARGV.clear 9 | IRB.start 10 | end 11 | task c: :console 12 | -------------------------------------------------------------------------------- /tasks/coverage.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | desc "Measure code coverage" 4 | task :coverage do 5 | begin 6 | original, ENV["COVERAGE"] = ENV["COVERAGE"], "true" 7 | Rake::Task["spec"].invoke 8 | ensure 9 | ENV["COVERAGE"] = original 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /tasks/spec.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | begin 4 | require "rspec/core/rake_task" 5 | 6 | desc "Run all specs" 7 | RSpec::Core::RakeTask.new(:spec) do |task| 8 | task.pattern = "spec/{unit,integration}{,/*/**}/*_spec.rb" 9 | end 10 | 11 | namespace :spec do 12 | desc "Run unit specs" 13 | RSpec::Core::RakeTask.new(:unit) do |task| 14 | task.pattern = "spec/unit{,/*/**}/*_spec.rb" 15 | end 16 | 17 | desc "Run integration specs" 18 | RSpec::Core::RakeTask.new(:integration) do |task| 19 | task.pattern = "spec/integration{,/*/**}/*_spec.rb" 20 | end 21 | end 22 | 23 | rescue LoadError 24 | %w[spec spec:unit spec:integration].each do |name| 25 | task name do 26 | $stderr.puts "In order to run #{name}, do `gem install rspec`" 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /tty-color.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "lib/tty/color/version" 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = "tty-color" 7 | spec.version = TTY::Color::VERSION 8 | spec.authors = ["Piotr Murach"] 9 | spec.email = ["piotr@piotrmurach.com"] 10 | spec.summary = "Terminal color capabilities detection." 11 | spec.description = "Terminal color capabilities detection." 12 | spec.homepage = "https://ttytoolkit.org" 13 | spec.license = "MIT" 14 | spec.metadata = { 15 | "allowed_push_host" => "https://rubygems.org", 16 | "bug_tracker_uri" => "https://github.com/piotrmurach/tty-color/issues", 17 | "changelog_uri" => 18 | "https://github.com/piotrmurach/tty-color/blob/master/CHANGELOG.md", 19 | "documentation_uri" => "https://www.rubydoc.info/gems/tty-color", 20 | "funding_uri" => "https://github.com/sponsors/piotrmurach", 21 | "homepage_uri" => spec.homepage, 22 | "rubygems_mfa_required" => "true", 23 | "source_code_uri" => "https://github.com/piotrmurach/tty-color" 24 | } 25 | spec.files = Dir["lib/**/*"] 26 | spec.extra_rdoc_files = ["README.md", "CHANGELOG.md", "LICENSE.txt"] 27 | spec.bindir = "exe" 28 | spec.require_paths = ["lib"] 29 | spec.required_ruby_version = ">= 2.0.0" 30 | 31 | spec.add_development_dependency "rake" 32 | spec.add_development_dependency "rspec", ">= 3.0" 33 | end 34 | --------------------------------------------------------------------------------