├── .editorconfig ├── .github └── workflows │ └── test.yml ├── .gitignore ├── .rspec ├── CODE_OF_CONDUCT.md ├── ChangeLog.md ├── Gemfile ├── MIT-LICENSE.txt ├── README.md ├── Rakefile ├── debugging.gemspec ├── lib ├── debugging.rb └── debugging │ ├── all.rb │ ├── at.rb │ ├── beep.rb │ ├── callstack.rb │ ├── howtocall.rb │ ├── q.rb │ ├── re.rb │ └── version.rb └── spec ├── howtocall_spec.rb ├── q_spec.rb ├── re_spec.rb └── spec_helper.rb /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.{md,rdoc,txt}] 11 | indent_size = 4 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | name: Ruby ${{ matrix.ruby }} (${{ matrix.os }}) 8 | if: "!contains(github.event.head_commit.message, '[skip ci]')" 9 | strategy: 10 | matrix: 11 | ruby: 12 | - 3.2 13 | - 3.1 14 | - '3.0' 15 | - 2.7 16 | - jruby 17 | - truffleruby 18 | os: 19 | - ubuntu-latest 20 | # - macos-latest 21 | runs-on: ${{matrix.os}} 22 | steps: 23 | - uses: actions/checkout@v2 24 | - name: Set up Ruby 25 | uses: ruby/setup-ruby@v1 26 | with: 27 | ruby-version: ${{matrix.ruby}} 28 | bundler-cache: true 29 | - name: Run tests 30 | run: bundle exec rake 31 | 32 | test-windows: 33 | name: Ruby ${{ matrix.ruby }} (windows-latest) 34 | if: "!contains(github.event.head_commit.message, '[skip ci]')" 35 | strategy: 36 | matrix: 37 | ruby: 38 | - 3.1 39 | - '3.0' 40 | - 2.7 41 | runs-on: windows-latest 42 | steps: 43 | - uses: actions/checkout@v2 44 | - name: Set up Ruby 45 | uses: ruby/setup-ruby@v1 46 | with: 47 | ruby-version: ${{matrix.ruby}} 48 | bundler-cache: true 49 | - run: cinst ansicon 50 | - name: Run tests 51 | run: bundle exec rake 52 | 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | pkg 3 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --colour --format documentation 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at conduct@janlelis.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | ## ChangeLog 2 | 3 | ### 2.1.0 / 2022-12-25 4 | 5 | * Remove `debugging/mof`; use looksee, object shadow, or IRB's own ls for reliable lookup path inspection 6 | * Fix that `debugging/all` also loads howtocall 7 | 8 | ### 2.0.0 / 2021-12-30 9 | 10 | * Remove `debugging/repl`, since Ruby now has `binding.irb` 11 | 12 | ### 1.1.2 / 2020-12-29 13 | 14 | * Relax required Ruby version 15 | 16 | ### 1.1.1 / 2017-03-18 17 | 18 | * Make howtocall private 19 | * Relax paint dependency (allow paint versions 2.x) 20 | 21 | ### 1.1.0 / 2015-03-26 22 | 23 | * Added: 24 | * howtocall 25 | * Change output from `mof`, now only returns singleton methods per module for modules 26 | * Make q compatible with paint ~> 1.0 27 | * Drop support for Ruby 1 28 | 29 | 30 | ### 1.0.2 / 2015-01-24 31 | 32 | * Bump binding.repl version 33 | 34 | 35 | ### 1.0.1 / 2014-02-15 36 | 37 | * Bump binding.repl version 38 | 39 | 40 | ### 1.0.0 / 2014-01-19 41 | 42 | * Adjusted concept: Only helper method style 43 | * Removed: 44 | * dd 45 | * binding.vars 46 | 47 | * Added: 48 | * beep 49 | * repl 50 | 51 | * Renamed: 52 | * oo -> at 53 | * cc -> callstack 54 | * mm -> mof 55 | * regexp_visualize -> re 56 | 57 | * Method List: Display all available ancestors by default and add third argument for grepping 58 | * Moved from zucker 13.1 gem into its own gem 59 | 60 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | ### ### ### 6 | 7 | # 3.2 workaround for RSpec 2.99, see https://bugs.ruby-lang.org/issues/17391 8 | def File.exists?(f)exist?(f)end unless defined? File.exists? 9 | 10 | ### ### ### 11 | 12 | -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2022 Jan Lelis 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ruby Print Debugging [![version](https://badge.fury.io/rb/debugging.svg)](https://badge.fury.io/rb/debugging) [](https://github.com/janlelis/debugging/actions?query=workflow%3ATest) 2 | 3 | Helps you to introspect and debug your code. 4 | 5 | 6 | ## Setup 7 | 8 | Install gem: 9 | 10 | ``` 11 | $ gem install debugging 12 | ``` 13 | 14 | 15 | In Ruby: 16 | 17 | ```ruby 18 | require 'debugging/all' 19 | ``` 20 | 21 | Instead of requiring all, you can also require only one function, e.g: 22 | 23 | ```ruby 24 | require 'debugging/q' 25 | ``` 26 | 27 | In a bundler project, you will need to add the gem to your project's `Gemfile`: 28 | 29 | ```ruby 30 | gem 'debugging', require: 'debugging/all' 31 | ``` 32 | 33 | ## Methods 34 | ### at(label = nil) 35 | 36 | Prints out that a specific point in a script has been reached. 37 | 38 | ``` 39 | [label] @ method `...', line ... of file .... 40 | ``` 41 | 42 | ### beep 43 | 44 | Lets your terminal bell ring. 45 | 46 | ### callstack 47 | 48 | Prints out your current callstack. For example: 49 | 50 | ``` 51 |
52 | start 53 | catch 54 | block in start 55 | eval_input 56 | each_top_level_statement 57 | catch 58 | block in each_top_level_statement 59 | loop 60 | block (2 levels) in each_top_level_statement 61 | block in eval_input 62 | signal_status 63 | block (2 levels) in eval_input 64 | evaluate 65 | evaluate 66 | eval 67 | irb_binding 68 | ``` 69 | 70 | ### howtocall(obj = self, method_or_proc) 71 | 72 | Displays parameter names and types for a proc or method (identified by a symbol): 73 | 74 | ```ruby 75 | def function(a, b = 3, &c) 76 | end 77 | howtocall :function #=> function(a, b, &c) 78 | ``` 79 | 80 | What is not visible in the example above: All optional parameters are displayed underlined. 81 | 82 | If you want to access a function that is defined on an other object than the current one, 83 | you can pass it as an optional parameter: 84 | 85 | ```ruby 86 | howtocall FileUtils, :cd #=> cd(dir, options, &block) 87 | howtocall Open3, :popen3 #=> popen3(*cmd, **opts, &block) 88 | 89 | ``` 90 | 91 | An example with lambdas and keyword arguments: 92 | 93 | ```ruby 94 | a = ->(filter: /\A.*\z/, string:){ string[filter] } 95 | howtocall a #=> call(string:, filter:) 96 | ``` 97 | 98 | ### q(*args) 99 | 100 | Like `Kernel#p`, but with colors on one line: 101 | 102 | ```ruby 103 | q :is_like, ?p, "but on one line" 104 | ``` 105 | 106 | ### re(string, regex, groups = nil) 107 | 108 | Assists you when matching regexes againts strings. Try this one: 109 | 110 | ```ruby 111 | re "mail@janlelis.de", /\b([A-Z0-9._%+-]+)@([A-Z0-9.-]+\.[A-Z]{2,10})\b/i, 0..2 112 | ``` 113 | 114 | ## J-_-L 115 | 116 | Copyright (c) 2010-2022 Jan Lelis. MIT License. Originated from the 117 | [zucker](https://github.com/janlelis/sugar_refinery) gem. 118 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # # # 2 | # Get gemspec info 3 | 4 | gemspec_file = Dir['*.gemspec'].first 5 | gemspec = eval File.read(gemspec_file), binding, gemspec_file 6 | info = "#{gemspec.name} | #{gemspec.version} | " \ 7 | "#{gemspec.runtime_dependencies.size} dependencies | " \ 8 | "#{gemspec.files.size} files" 9 | 10 | 11 | # # # 12 | # Gem build and install task 13 | 14 | desc info 15 | task :gem do 16 | puts info + "\n\n" 17 | print " "; sh "gem build #{gemspec_file}" 18 | FileUtils.mkdir_p 'pkg' 19 | FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", 'pkg' 20 | puts; sh %{gem install --no-document pkg/#{gemspec.name}-#{gemspec.version}.gem} 21 | end 22 | 23 | 24 | # # # 25 | # Start an IRB session with the gem loaded 26 | 27 | desc "#{gemspec.name} | IRB" 28 | task :irb do 29 | sh "irb -I ./lib -r #{gemspec.name.gsub '-','/'}" 30 | end 31 | 32 | 33 | # # # 34 | # Spec 35 | 36 | desc "#{gemspec.name} | Spec" 37 | task :spec do 38 | sh "rspec" 39 | end 40 | 41 | task :test => :spec 42 | task :default => :spec 43 | -------------------------------------------------------------------------------- /debugging.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require File.expand_path('../lib/debugging/version', __FILE__) 4 | 5 | Gem::Specification.new do |gem| 6 | gem.name = "debugging" 7 | gem.version = Debugging::VERSION 8 | gem.summary = 'Print debugging helpers' 9 | gem.description = 'Utilities for better "print debugging"' 10 | gem.license = "MIT" 11 | gem.authors = ["Jan Lelis"] 12 | gem.email = ["hi@ruby.consulting"] 13 | gem.homepage = "https://github.com/janlelis/debugging" 14 | 15 | gem.files = Dir['{**/}{.*,*}'].select { |path| File.file?(path) && path !~ /pkg/ } 16 | gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } 17 | gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) 18 | gem.require_paths = ['lib'] 19 | gem.metadata = { "rubygems_mfa_required" => "true" } 20 | 21 | gem.required_ruby_version = '>= 2.0', '< 4.0' 22 | 23 | gem.add_dependency 'paint', '>= 0.9', '< 3.0' 24 | 25 | gem.add_development_dependency 'rake', '~> 13.0' 26 | gem.add_development_dependency 'rspec', '~> 2.99' 27 | end 28 | -------------------------------------------------------------------------------- /lib/debugging.rb: -------------------------------------------------------------------------------- 1 | require_relative 'debugging/version' 2 | require 'paint' 3 | 4 | Object.send :include, Debugging 5 | -------------------------------------------------------------------------------- /lib/debugging/all.rb: -------------------------------------------------------------------------------- 1 | %w[ 2 | at 3 | beep 4 | callstack 5 | howtocall 6 | q 7 | re 8 | ].each{ |m| require_relative(m) } 9 | -------------------------------------------------------------------------------- /lib/debugging/at.rb: -------------------------------------------------------------------------------- 1 | require 'debugging' 2 | 3 | module Debugging 4 | private 5 | 6 | def at(label = nil) 7 | caller[0].rindex( /:(\d+)(:in (`.*'))?$/ ) 8 | puts "#{ label && Paint["#{label} ", :yellow] }@"\ 9 | " #{ $3 && "method #{ Paint[$3, :red] }, " }line "\ 10 | "#{ Paint[$1, :blue]} of file #{ Paint[$`, :green]}" 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/debugging/beep.rb: -------------------------------------------------------------------------------- 1 | require 'debugging' 2 | 3 | module Debugging 4 | private 5 | 6 | def beep 7 | $stdout.print "\a" 8 | end 9 | end -------------------------------------------------------------------------------- /lib/debugging/callstack.rb: -------------------------------------------------------------------------------- 1 | require 'debugging' 2 | 3 | module Debugging 4 | private 5 | 6 | def callstack 7 | caller.reverse.map{ |m| 8 | m.rindex( /:\d+(:in `(.*)')?$/ ) 9 | $2 10 | }.compact.each.with_index{ |m, i| 11 | puts " "*i + m 12 | } 13 | 14 | nil 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/debugging/howtocall.rb: -------------------------------------------------------------------------------- 1 | require 'debugging' 2 | 3 | module Debugging 4 | private 5 | 6 | def howtocall(object = self, method_or_proc) 7 | if method_or_proc.is_a? Proc 8 | params = method_or_proc.parameters 9 | template = "call(%s)" 10 | else 11 | unless method_or_proc.is_a?(Method) || method_or_proc.is_a?(UnboundMethod) 12 | method_or_proc = object.method(method_or_proc) 13 | end 14 | params = method_or_proc.parameters 15 | template = "#{method_or_proc.name}(%s)" 16 | end 17 | 18 | sig = params.map{ |type, name| 19 | param = "" 20 | param << "*" if type == :rest 21 | param << "**" if type == :keyrest 22 | param << "&" if type == :block 23 | name = ?? if !name && !(type == :rest || type == :keyrest) 24 | if type == :opt || type == :key 25 | param << Paint[name, :underline] 26 | else 27 | param << name.to_s 28 | end 29 | param << ":" if type == :key || type == :keyreq 30 | param 31 | }*", " 32 | 33 | puts template %(sig) 34 | nil 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/debugging/q.rb: -------------------------------------------------------------------------------- 1 | require 'debugging' 2 | 3 | module Debugging 4 | private 5 | 6 | def q(*args) 7 | puts args.map{ |e| Paint[e.inspect, Paint.random] }*' ' unless args.empty? 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/debugging/re.rb: -------------------------------------------------------------------------------- 1 | require 'debugging' 2 | 3 | module Debugging 4 | private 5 | 6 | def re(string, regex, groups = nil) 7 | if regex =~ string 8 | if !groups 9 | puts $` + Paint[$&, :green] + $' 10 | else 11 | Array( groups ).each{ |group_nr| 12 | begin 13 | raise IndexError unless $~[group_nr] 14 | gr_string = string.dup 15 | gr_string[ $~.end( group_nr ), 0 ] = Paint::NOTHING 16 | gr_string[ $~.begin( group_nr ), 0 ] = Paint.color(:green) 17 | puts group_nr.to_s + ': ' + gr_string 18 | rescue IndexError 19 | puts group_nr.to_s + ': ' + Paint['no match', :red] 20 | end 21 | } 22 | end 23 | else 24 | puts Paint['no match', :red] 25 | end 26 | 27 | nil 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/debugging/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Debugging 4 | VERSION = "2.1.0" 5 | end 6 | -------------------------------------------------------------------------------- /spec/howtocall_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'debugging/howtocall' 3 | 4 | describe "howtocall" do 5 | it "displays method parameters" do 6 | def function(a, b) 7 | end 8 | 9 | expect( capture_stdout{ howtocall :function } ).to eq "function(a, b)\n" 10 | end 11 | 12 | it "underlines optional parameters" do 13 | def function(a, b = 3) 14 | end 15 | 16 | expect( capture_stdout{ howtocall :function } ).to eq "function(a, \e[4mb\e[0m)\n" 17 | end 18 | 19 | it "shows block parameters" do 20 | def function(a, &b) 21 | end 22 | 23 | expect( capture_stdout{ howtocall :function } ).to eq "function(a, &b)\n" 24 | end 25 | 26 | it "optionally takes an object where the method shoud be looked for (if not self)" do 27 | module Klass 28 | def self.function(a,b) 29 | end 30 | end 31 | 32 | expect( capture_stdout{ howtocall Klass, :function } ).to eq "function(a, b)\n" 33 | end 34 | 35 | it "appends : for keyword arguments" do 36 | def function(a: 42, b: 43) 37 | end 38 | 39 | expect( capture_stdout{ howtocall :function } ).to eq "function(\e[4ma\e[0m:, \e[4mb\e[0m:)\n" 40 | end 41 | 42 | it "shows *splats and keyword **splats" do 43 | def function(*cmd, **opts) 44 | end 45 | 46 | expect( capture_stdout{ howtocall :function } ).to eq "function(*cmd, **opts)\n" 47 | end 48 | 49 | it "shows ? for array deconstructor parameters" do 50 | def function((a, b)) 51 | end 52 | 53 | expect( capture_stdout{ howtocall :function } ).to eq "function(?)\n" 54 | end 55 | 56 | it "also works for procs" do 57 | lambda = ->(a, b){} 58 | 59 | expect( capture_stdout{ howtocall lambda } ).to eq "call(a, b)\n" 60 | end 61 | 62 | if RUBY_ENGINE == "ruby" || RUBY_ENGINE == "jruby" 63 | context "[native methods]" do 64 | it "shows ? instead of parameter names for fixed amount of parameters" do 65 | expect( capture_stdout{ howtocall :is_a? } ).to eq "is_a?(?)\n" 66 | end 67 | 68 | it "shows * instead of parameters for variable amount of parameters" do 69 | expect( capture_stdout{ howtocall :puts } ).to eq "puts(*)\n" 70 | end 71 | end 72 | end 73 | 74 | end 75 | -------------------------------------------------------------------------------- /spec/q_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'debugging/q' 3 | 4 | describe 'q' do 5 | it "should output the same as p for a single arg" do 6 | expect( 7 | Paint.unpaint(capture_stdout{q /some object/}) 8 | ).to eq capture_stdout{p /some object/} 9 | end 10 | 11 | it "should output the same as p but for multiple args one one line, values separated by two spaces" do 12 | expect( 13 | Paint.unpaint(capture_stdout{ 14 | q 1, "1", 2..5, [], {:hallo => :du}, nil, true 15 | } 16 | ).chop ).to eq capture_stdout{ 17 | p 1, "1", 2..5, [], {:hallo => :du}, nil, true 18 | }.chop.gsub( "\n", ' ' ) 19 | end 20 | end 21 | 22 | -------------------------------------------------------------------------------- /spec/re_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'debugging/re' 3 | 4 | describe 're' do 5 | let :regex do /\b([A-Z0-9._%+-]+)@([A-Z0-9.-]+\.[A-Z]{2,4})\b/i end # r from regular-expressions.info/email.html 6 | 7 | it 'should display a string where mark the found regex in green' do 8 | capture_stdout do 9 | re 'I do not contain an email address.', regex 10 | end.chomp.should == Paint.color(:red) + 'no match' + Paint::NOTHING 11 | end 12 | 13 | it 'should display "no match" if the regex could not be matched' do 14 | capture_stdout do 15 | re 'I contain an email address: mail@example.com', regex 16 | end.chomp.should == 'I contain an email address: ' + Paint.color(:green) + 'mail@example.com' + Paint::NOTHING + '' 17 | end 18 | 19 | it 'should display a string and mark the found regex group in green if group identifier is given as arg2' do 20 | capture_stdout do 21 | re 'mail@example.com', regex, 1 22 | end.chomp.should == '1: ' + Paint.color(:green) + 'mail' + Paint::NOTHING + '@example.com' 23 | end 24 | 25 | it 'should display "group identifier: no match" if the arg2 group could not be matched' do 26 | capture_stdout do 27 | re 'mail@example.com', regex, 3 28 | end.chomp.should == '3: ' + Paint.color(:red) + 'no match' + Paint::NOTHING 29 | end 30 | 31 | it 'should also take an array of group identfiers as arg2' do 32 | capture_stdout do 33 | re 'mail@example.com', regex, [0,1,2] 34 | end.chomp.should == '0: ' + Paint.color(:green) + 'mail@example.com' + Paint::NOTHING + "\n" + 35 | '1: ' + Paint.color(:green) + 'mail' + Paint::NOTHING + '@example.com' + "\n" + 36 | '2: mail@' + Paint.color(:green) + 'example.com' + Paint::NOTHING 37 | end 38 | end 39 | 40 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require 'stringio' 3 | 4 | def capture_stdout 5 | capture = StringIO.new 6 | restore, $stdout = $stdout, capture 7 | yield 8 | $stdout = restore 9 | capture.string 10 | end 11 | 12 | def capture_stderr 13 | capture = StringIO.new 14 | restore, $stderr = $stderr, capture 15 | yield 16 | $stderr = restore 17 | capture.string 18 | end 19 | --------------------------------------------------------------------------------