Repository: godfat/rib
Branch: master
Commit: 54d1f88d9c85
Files: 71
Total size: 132.8 KB
Directory structure:
gitextract_3eo0hgho/
├── .gitignore
├── .gitlab-ci.yml
├── .gitmodules
├── CHANGES.md
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── TODO.md
├── asciicast.json
├── bin/
│ ├── rib
│ ├── rib-all
│ ├── rib-auto
│ ├── rib-min
│ ├── rib-rack
│ └── rib-rails
├── lib/
│ ├── rib/
│ │ ├── all.rb
│ │ ├── api.rb
│ │ ├── app/
│ │ │ ├── auto.rb
│ │ │ ├── rack.rb
│ │ │ └── rails.rb
│ │ ├── config.rb
│ │ ├── core/
│ │ │ ├── completion.rb
│ │ │ ├── history.rb
│ │ │ ├── last_value.rb
│ │ │ ├── multiline.rb
│ │ │ ├── readline.rb
│ │ │ ├── squeeze_history.rb
│ │ │ └── strip_backtrace.rb
│ │ ├── core.rb
│ │ ├── debug.rb
│ │ ├── extra/
│ │ │ ├── autoindent.rb
│ │ │ ├── byebug.rb
│ │ │ ├── hirb.rb
│ │ │ ├── paging.rb
│ │ │ └── spring.rb
│ │ ├── more/
│ │ │ ├── anchor.rb
│ │ │ ├── beep.rb
│ │ │ ├── bottomup_backtrace.rb
│ │ │ ├── caller.rb
│ │ │ ├── color.rb
│ │ │ ├── edit.rb
│ │ │ ├── multiline_history.rb
│ │ │ └── multiline_history_file.rb
│ │ ├── more.rb
│ │ ├── plugin.rb
│ │ ├── runner.rb
│ │ ├── shell.rb
│ │ ├── test/
│ │ │ ├── history.rb
│ │ │ └── multiline.rb
│ │ ├── test.rb
│ │ └── version.rb
│ └── rib.rb
├── rib.gemspec
└── test/
├── core/
│ ├── test_completion.rb
│ ├── test_history.rb
│ ├── test_last_value.rb
│ ├── test_multiline.rb
│ ├── test_readline.rb
│ ├── test_squeeze_history.rb
│ └── test_strip_backtrace.rb
├── extra/
│ └── test_autoindent.rb
├── more/
│ ├── test_anchor.rb
│ ├── test_beep.rb
│ ├── test_caller.rb
│ ├── test_color.rb
│ └── test_multiline_history.rb
├── test_api.rb
├── test_plugin.rb
├── test_runner.rb
└── test_shell.rb
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/pkg/
/coverage/
================================================
FILE: .gitlab-ci.yml
================================================
stages:
- test
.test:
stage: test
image: ruby:${RUBY_VERSION}-bullseye
variables:
GIT_DEPTH: "1"
GIT_SUBMODULE_STRATEGY: recursive
GIT_SUBMODULE_PATHS: task
RUBYOPT: --enable-frozen-string-literal
before_script:
- bundle install --retry=3
- unset CI # Coverage doesn't work well with frozen literal
script:
- ruby -vr bundler/setup -S rake test
ruby:3.2:
extends:
- .test
variables:
RUBY_VERSION: '3.2'
ruby:3.3:
extends:
- .test
variables:
RUBY_VERSION: '3.3'
ruby:3.4:
extends:
- .test
variables:
RUBY_VERSION: '3.4'
jruby:latest:
extends:
- .test
image: jruby:latest
================================================
FILE: .gitmodules
================================================
[submodule "task"]
path = task
url = https://github.com/godfat/gemgem.git
================================================
FILE: CHANGES.md
================================================
# CHANGES
## Rib 1.6.2 -- 2026-01-20
### Bugs fixed
* [core/strip_backtrace] Now it works with backtrace quotes change from
`` ` `` to `'`
## Rib 1.6.2 -- 2026-01-19
### Bugs fixed
* [core/multiline] Now it works with prism parser
* [more/color] Now it works with backtrace quotes change from `` ` `` to `'`
## Rib 1.6.1 -- 2022-12-30
### Bugs fixed
* Fixed `rib rack` for constant resolution.
### Enhancement
* [more/color] Instead of using `$1` and `$2`, use `Regexp.last_match`.
It should be the same for MRI, but seems to be working better for JRuby.
Perhaps `$1` and `$2` is not thread local on JRuby?
## Rib 1.6.0 -- 2018-06-20
* [core/multiline] Support for JRuby 9.2.0.0 is fixed
* [more/beep] It would now beep every single time when any evaluation took
longer than the threshold.
* [more/color] Fix whenever the input is just `next` or `break`
* [more/bottomup_backtrace] This would no longer format backtrace twice
* [more/caller] It would now properly use the enabled plugins
* [extra/autoindent] It would now indent with `ensure` for `begin` and `def`.
Thanks @MITSUBOSHI https://github.com/godfat/rib/pull/21 and
@alpaca-tc https://github.com/godfat/rib/pull/17
* [extra/autoindent] It would now indent with `for`.
Thanks @MITSUBOSHI https://github.com/godfat/rib/pull/18
* [extra/autoindent] It would now indent with `()` and `[]`.
Thanks @MITSUBOSHI https://github.com/godfat/rib/pull/20 and
https://github.com/godfat/rib/pull/19
* [extra/byebug] This is now work-in-progress.
## Rib 1.5.4 -- 2017-10-23
* Removed unnecessary method definition for `puts`
## Rib 1.5.3 -- 2017-08-05
* Now we set trap only when the shell starts, and restore the old trap
after the shell stops. This should fix some problems using anchor inside
RSpec or Unicorn. They would no longer interfere with them.
* [core/multiline] Now we support backslash. See:
[Using backslash line continuation character results in syntax error](https://github.com/godfat/rib/issues/15)
## Rib 1.5.2 -- 2017-05-01
* We now `require 'rib/version'` from the beginning, avoid loading error
under bundler.
* Introduced `API#started_at` which is `config[:started_at]` for accessing
when Rib started.
* Introduced `API#inspect_result` which would inspect the result. The default
behaviour would just inspect the result, but if the result is not a string,
emit a warning. https://github.com/godfat/rib/issues/14
* Now all warnings would be printed after the result was printed. This would
make it easier to spot warnings.
* [more/color] It would now paint warnings.
* [more/anchor] Introduced `Rib.stop_anchors` to stop all nested anchors.
https://github.com/godfat/rib/issues/13
* Fixed Rib app detection for newer RubyGems
### Breaking changes
* Extending `Rib::Plugin` would no longer automatically also include `Rib`.
For compatibility concern, a `const_missing` is now defined in `Rib::Plugin`
so that using `Shell` would still refer to `Rib::Shell` for you, considering
that this might be a common pattern:
extend Rib::Plugin
Shell.use(self)
Note that this would be removed in the future, so please take this chance to
change it to:
extend Rib::Plugin
Rib::Shell.use(self)
## Rib 1.5.1 -- 2017-03-09
* [more/beep] This plugin would beep via `print "\a"` when the application
was loaded and it's been too long. Configure the time via
`Rib.config[:beep_threshold]`, default is 5 seconds.
## Rib 1.5.0 -- 2017-02-27
* Removed Ramaze direct support. Use Rack instead.
* Introduced API#format_backtrace
* Introduced API#puts
* [more/anchor] Fixed multiline support when anchoring on an object
* [more/caller] Added for showing formatted call stack
* [core/underscore] This is changed to `core/last_value`, and the API is
changed to `Rib.last_value` and `Rib.last_exception`. Surely this is less
intrusive and more compatible for things like `Rib.anchor 42` because
now literal integers are frozen and we cannot define methods on them.
Also, using `Rib.last_value` is surely more descriptive. Of course,
being able to type `_` is so much easier, but you could just add a plugin
which defines `def _; Rib.last_value; end` and keep using `_` for your
own taste!
## Rib 1.4.0 -- 2016-11-11
* Search Rib home by directories rather than config/history file.
* Respect prefix option for detecting Rib home.
* Update help message for `-n`, which won't load any config.
* Change `Rib.config[:config]` to `Rib.config_path`.
* [app/rails] Fix loading boot file when using prefix option.
* [app/auto] Fix two variable shadowing warnings.
## Rib 1.3.1 -- 2016-11-03
* [core/strip_backtrace], [more/color] No longer show `./` for current path.
This would be more friendly to some editors like Sublime.
## Rib 1.3.0 -- 2016-06-28
* Now `rib` would accept `-p` or `--prefix` to allow setting where we want to
load the application. This is useful when we don't want to `cd` into a
directory and `rib auto` or `rib rails` from there.
## Rib 1.2.91 -- 2016-01-06
* [core/multiline] Fixed a case for JRuby 9.0.4.0.
* [extra/paging] Disable paging if `tput` is not found.
* [extra/spring] Require `rib/extra/spring` in your `~/.spring` to enable
Rails Spring support. #11 (thanks @swrobel)
## Rib 1.2.9 -- 2015-09-23
* [extra/paging] Disable paging if your terminal is nil. (e.g. on Heroku)
## Rib 1.2.8 -- 2015-09-23
* [extra/paging] Disable paging if your terminal is dumb. (e.g. on Heroku)
## Rib 1.2.7 -- 2015-01-28
* [more/bottomup_backtrace] A new plugin which prints the backtrace bottom-up.
Ref: <http://yellerapp.com/posts/2015-01-22-upside-down-stacktraces.html>
## Rib 1.2.6 -- 2014-11-07
* [extra/autoindent] Now `module_function` would indent correctly.
* [extra/autoindent] Now `else` in `case` would indent correctly.
* [extra/autoindent] Fixed printing end clause twice. (performance fix)
* [extra/multiline] Fixed in some cases it's not recognized as multiline
in Rubinius (rbx).
## Rib 1.2.5 -- 2014-03-13
* Fixed binding. Sorry my bad.
## Rib 1.2.4 -- 2014-03-13
* Fixed a regression introduced in 1.2.0. Now `rib all -e 'p 123'` should
work properly. Previously -e is ignored after rib apps.
* Fixed a long standing Windows issue, where `rib all` did not work because
there's no `which` on Windows. Now we fall back to `where`.
* Warn on removing main method on `TOPLEVEL_BINDING`. Not sure if this
would happen, but at least we could have a warning.
## Rib 1.2.3 -- 2014-02-08
* [extra/paging] Properly disable paging if less or ENV['PAGER'] is not
available.
## Rib 1.2.2 -- 2014-01-23
* From now on, we support project specific config file located on
"./.rib/config.rb". Note that if there's a project specific config file,
your home config would not be loaded at all. The history file would also
be put into "./.rib/history.rb". You might want to ignore it from your
repository to avoid leaking confidential information.
* [extra/paging] Now we strip ANSI sequences before calculating if we need
a pager. This should make it much more accurate.
## Rib 1.2.1 -- 2014-01-18
* Fixed a bug where it cannot properly elegantly handle errors when loading
the config file.
* [extra/paging] This plugin would try to use $PAGER and by default less to
paginate for output which cannot fit in a screen.
* [more/edit] Now by default it would pick vim if $EDITOR is not set.
## Rib 1.2.0 -- 2014-01-17
* We no longer really eval on TOPLEVEL_BINDING, but a private binding
derived from TOPLEVEL_BINDING. This is due to RubyGems bin stub would
actually pollute TOPLEVEL_BINDING, leaving `str` and `version` as
local variables. I would like to avoid them, thus introducing this change.
Please let me know if this breaks anything, thanks!
* [core/multiline] Fixed a multiline detection for Rubinius.
## Rib 1.1.6 -- 2013-08-14
* [more/color] Fixed inspecting recursive array and hash.
## Rib 1.1.5 -- 2013-07-11
* Fixed `rib -h` with commands don't have a description.
* Added a description for `rib rack`
## Rib 1.1.4 -- 2013-07-11
* Further fixed a bug for displaying a BasicObject. Rib should never crash.
* Added `rib-rack` executable which could load the app in config.ru,
accessible from calling `app` in the console. Also works for `rib-auto`
## Rib 1.1.3 -- 2013-05-08
* Fixed a bug where if user input doesn't respond to `==` would crash rib.
## Rib 1.1.2 -- 2013-04-02
* [core/multiline] Ruby 2.0 compatibility.
## Rib 1.1.1 -- 2013-01-25
* Fixed some multiline issue with Rubinius and JRuby.
* Properly indent for multiline prompt.
* Removed ripl compatibility layer.
* Only retry 5 times upon failures. This prevents from infinite retries.
* Don't retry on quiting.
* Added a half-baked debugger support. Try it with:
`require 'rib/extra/debugger'; Rib.debug`
## Rib 1.1.0 -- 2012-07-18
* Support for Ruby 1.8 is dropped.
* Now `Rib::Plugin` should be extended to the module, instead of included.
This fits more naturally with Ruby, but not really compatible with Ruby 1.8?
* [more/anchor] Fixed a bug where you run rib in top level while anchor in
the other source, exit from the inner shell would break from the original
call. Now you can safely exit from the inner shell and keep doing the
original work.
## Rib 1.0.5 -- 2012-05-15
* [app/rails] Fixed SystemStackError issue. It's because ConsoleMethods
should not pollute the Object, redefining `app` method.
## Rib 1.0.4 -- 2012-03-20
* [core/multiline] Fixed a corner case:
``` ruby
1/1.to_i +
1
```
* [rib] Do not crash because of a loop error. Try to relaunch the shell.
## Rib 1.0.3 -- 2012-01-21
### Bugs fixes
* [rib-rails] Fixed sandbox mode.
* [rib-rails] Bring back `reload!`, `new_session`, and `app` for Rails 3.2.0
## Rib 1.0.2 -- 2011-12-24
### Bugs fixes
* [more/multiline_history] Make sure values are initialized even if
before_loop is called later. This helps us enable plugins on the fly.
## Rib 1.0.1 -- 2011-12-15
### Incompatible changes
* [rib] Keyword `quit` to exit rib is removed, preferring `exit`.
### Bugs fixes
* [rib] Now you exit rib with ` exit`. Thanks @ayamomiji
* [rib] Fixed -e, --eval binding. It should be TOPLEVEL_BINDING
### Enhancement
* [core/history, more/color, more/multiline_history_file, extra/autoindent]
Make sure values are initialized even if before_loop is called later.
This helps us enable plugins on the fly.
* [extra/autoindent] Now it depends on history plugin as well. This is not
really needed, but would help to reduce plugins ordering issue.
## Rib 1.0.0 -- 2011-11-05
### Bugs fixes
* [more/color] Fixed a bug for displaying `1/0`. Fixed #4, thanks @bootleq
## Rib 0.9.9 -- 2011-10-26
### Bugs fixes
* [more/color] Fixed Windows coloring support.
* [more/color] Properly reset ANSI sequence.
### Enhancement
* [commands] Extract commands description under `__END__` in the commands.
Please read [rib-rest-core][] as an example.
* [rib] Always show original errors if anything is wrong.
[rib-rest-core]: https://github.com/cardinalblue/rest-core/blob/rest-core-0.7.0/bin/rib-rest-core#L21-22
## Rib 0.9.5 -- 2011-09-03
* [rib-rails] Fixed Rails3 (sandbox) and Rails2 (env) console. Thanks bootleq
* [rib-min] Fixed not being really minimum
* [rib] Now you can run it with `rib -wdIlib`, isn't it convenient?
It's equivalent to `rib -w -d -I lib` or `rib -w -d -I=lib`
## Rib 0.9.4 -- 2011-09-01
* [rib-rails] So now we replicated what Rails did for its console, both for
Rails 2 and Rails 3. You can now fully use `rib rails` or `rib auto` as
`rails console` or `./script/console` in respect to Rails 2 or 3. For
example, it works for:
rib auto production
rib rails production
rib auto test --debugger # remember to add ruby-debug(19)? to Gemfile
rib auto test --sandbox
rib rails test --debugger --sandbox
It should also make Rails 3 print SQL log to stdout. Thanks tka.
## Rib 0.9.3 -- 2011-08-28
* [rib] Calling `Rib.shell` would no longer automatically `require 'rib/core'`
anymore. This is too messy. We should only do this in `bin/rib`. See:
commit #7a97441afeecae80f5493f4e8a4a6ba3044e2c33
require 'rib/more/anchor'
Rib.anchor 123
Should no longer crashed... Thanks Andrew.
## Rib 0.9.2 -- 2011-08-25
* [extra/autoindent] It has been greatly improved. A lot more accurate.
* [extra/autoindent] Fixed a bug when you're typing too fast upon rib
launching, it might eat your input. Thanks bootleq.
## Rib 0.9.1 -- 2011-08-19
* [extra/autoindent] Autoindent plugin help you indent multiline editing.
Note: This plugin is depending on [readline_buffer][], thus GNU Readline.
* [ripl] After `require 'rib/ripl'`, ripl plugins should be usable for rib.
* [rib] Introduce `ENV['RIB_HOME']` to set where to store config and history.
By default, it's `~/.rib` now, but it would first search for existing
config or history, which would first try to see `~/.rib/config.rb`, and
then `~/.rib/history.rb`. If Rib can find anything there, then `RIB_HOME`
would be set to `~/.rib`, the same goes to `~/.config/rib`.
In short, by default `RIB_HOME` is `~/.rib`, but the old `~/.config/rib`
still works.
[readline_buffer]: https://github.com/godfat/readline_buffer
## Rib 0.9.0 -- 2011-08-14
* First serious release!
* So much enhancement over ripl-rc!
================================================
FILE: Gemfile
================================================
source 'https://rubygems.org'
gemspec
gem 'rake'
gem 'pork'
gem 'muack'
gem 'bond'
gem 'hirb'
gem 'simplecov', :require => false if ENV['COV']
gem 'coveralls', :require => false if ENV['CI']
platforms :ruby do
gem 'readline_buffer'
end
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# Rib [](https://gitlab.com/godfat/rib/-/pipelines)
by Lin Jen-Shin ([godfat](https://godfat.org))
## LINKS:
* [github](https://github.com/godfat/rib)
* [rubygems](https://rubygems.org/gems/rib)
* [rdoc](https://rubydoc.info/github/godfat/rib)
* [issues](https://github.com/godfat/rib/issues) (feel free to ask for support)
## DESCRIPTION:
Ruby-Interactive-ruBy -- Yet another interactive Ruby shell
Rib is based on the design of [ripl][] and the work of [ripl-rc][], some of
the features are also inspired by [pry][]. The aim of Rib is to be fully
featured and yet very easy to opt-out or opt-in other features. It shall
be simple, lightweight and modular so that everyone could customize Rib.
[ripl]: https://github.com/cldwalker/ripl
[ripl-rc]: https://github.com/godfat/ripl-rc
[pry]: https://github.com/pry/pry
## REQUIREMENTS:
* Tested with MRI (official CRuby) and JRuby.
* All gem dependencies are optional, but it's highly recommended to use
Rib with [bond][] for tab completion.
[bond]: https://github.com/cldwalker/bond
## INSTALLATION:
gem install rib
## SYNOPSIS:

### As an interactive shell
As IRB (reads `~/.rib/config.rb` writes `~/.rib/history.rb`)
rib
As Rails console
rib rails
You could also run in production and pass arguments normally as you'd do in
`rails console` or `./script/console`
rib rails production --sandbox --debugger
Note: You might need to add ruby-debug or ruby-debug19 to your Gemfile if
you're passing --debugger and using bundler together.
For [Rails Spring](https://github.com/rails/spring) support, put this line
in your `~/.spring.rb`:
require 'rib/extra/spring'
As Rack console
rib rack
As a console for whichever the app in the current path
it should be (for now, it's either Rails or Rack)
rib auto
If you're trying to use `rib auto` for a Rails app, you could also pass
arguments as if you were using `rib rails`. `rib auto` is merely passing
arguments.
rib auto production --sandbox --debugger
As a fully featured interactive Ruby shell (as ripl-rc)
rib all
As a fully featured app console (yes, some commands could be used together)
rib all auto # or `rib auto all`, the order doesn't really matter
#### Customization
You can customize Rib's behaviour by setting a config file located at
`$RIB_HOME/config.rb`, or `./.rib/config.rb`, or `~/.rib/config.rb`, or
`~/.config/rib/config.rb`, searched by respected order. The default
would be `~/.rib/config.rb`. Since it's merely a Ruby script which would
be loaded into memory before launching Rib shell session, You can put any
customization or monkey patch there. Personally, I use all plugins provided
by Rib.
My Personal [~/.config/rib/config](https://github.com/godfat/dev-tool/blob/master/.config/rib/config.rb)
As you can see, putting `require 'rib/all'` into config file is exactly the
same as running `rib all` without a config file. What `rib all` would do is
merely require the file, and that file is also merely requiring all plugins,
but without **extra plugins**, which you should enable them one by one. This
is because most extra plugins are depending on other gems, or hard to work
with other plugins, or having strong personal tastes, so you won't want to
enable them all. Suppose you only want to use the core plugins and color
plugin, you'll put this into your config file:
``` ruby
require 'rib/core'
require 'rib/more/color'
```
You can also write your plugins there. Here's another example:
``` ruby
require 'rib/core'
require 'pp'
Rib.config[:prompt] = '$ '
module RibPP
Rib::Shell.send(:include, self)
def format_result result
result_prompt + result.pretty_inspect
end
end
```
So that we override the original format_result to pretty_inspect the result.
You can also build your own gem and then simply require it in your config
file. To see a list of overridable API, please read [api.rb][]
[api.rb]: https://github.com/godfat/rib/blob/master/lib/rib/api.rb
#### Disable enabled plugins
While it's convenient to just `require 'rib/all'`, you might not want to use
all the plugins. No worries, you don't have to list everything in order to
not use something. For example, you might not get used to `bottomup_backtrace`
and don't want to use it. You could put this in your config:
``` ruby
require 'rib/all'
Rib::BottomupBacktrace.disable
```
This could disable `bottomup_backtrace` so you get regular top-down backtrace
with all other plugins. This is particularly useful whenever there's a bug
in one of the plugins, and you might need to disable some plugins in order to
debug. You could always enable it again with:
``` ruby
Rib::BottomupBacktrace.enable
```
You could do this any time, in the config, or in the shell session. No need to
restart anything, because it takes effect immediately.
#### Rib home and history file
Rib home is used to store a config file and a history file, which is
searched in this order:
* $RIB_HOME
* ./.rib
* ~/.rib
* ~/.config/rib
Rib would stop searching whenever the directory is found. If none could be
found, the default would be:
* ~/.rib
So the default history file would be located at `~/.rib/history.rb`.
#### Project config and history
Since `./.rib` would be searched before `~/.rib`, you could create project
level config at the project directory, and the history would also be
separated from each other, located at the respected `./.rib/history.rb`.
To do this, you don't really have to create a project config. Creating an
empty directory for Rib home at the project directory would also work.
#### Project directory and command line options
You could set the project directory by using `-p, --prefix` command line
option. So consider this:
cd ~/project
rib auto
Would work the same as:
cd /tmp
rib -p ~/project auto
And the project config and history would be located at `~/project/.rib`.
To check for more command line options, run `rib -h`:
```
Usage: rib [ruby OPTIONS] [rib OPTIONS] [rib COMMANDS]
ruby options:
-e, --eval LINE Evaluate a LINE of code
-d, --debug Set debugging flags (set $DEBUG to true)
-w, --warn Turn warnings on (set $-w and $VERBOSE to true)
-I, --include PATH Specify $LOAD_PATH (may be used more than once)
-r, --require LIBRARY Require the library, before executing your script
rib options:
-c, --config FILE Load config from FILE
-p, --prefix PATH Prefix to locate the app. Default to .
-n, --no-config Suppress loading ~/.config/rib/config.rb
-h, --help Print this message
-v, --version Print the version
rib commands:
all Load all recommended plugins
auto Run as Rails or Rack console (auto-detect)
min Run the minimum essence
rack Run as Rack console
rails Run as Rails console
```
#### Basic configuration
Rib.config | Functionality
-------------------------- | -------------------------------------------------
ENV['RIB_HOME'] | Specify where Rib should store config and history
Rib.config[:name] | The name of this shell
Rib.config[:result_prompt] | Default is "=>"
Rib.config[:prompt] | Default is ">>"
Rib.config[:binding] | Context, default: TOPLEVEL_BINDING
Rib.config[:exit] | Commands to exit, default [nil] # control+d
#### Plugin specific configuration
Rib.config | Functionality
------------------------------ | ---------------------------------------------
Rib.config[:completion] | Completion: Bond config
Rib.config[:history_file] | Default is "~/.rib/history.rb"
Rib.config[:history_size] | Default is 500
Rib.config[:color] | A hash of Class => :color mapping
Rib.config[:autoindent_spaces] | How to indent? Default is two spaces: ' '
Rib.config[:beep_threshold] | When it should beep? Default is 5 seconds
#### List of core plugins
``` ruby
require 'rib/core' # You get all of the followings:
```
* `require 'rib/core/completion'`
Completion from [bond][].
* `require 'rib/core/history'`
Remember history in a history file.
* `require 'rib/core/strip_backtrace'`
Strip backtrace before Rib.
* `require 'rib/core/readline'`
Readline support.
* `require 'rib/core/multiline'`
You can interpret multiple lines.
* `require 'rib/core/squeeze_history'`
Remove duplicated input from history.
* `require 'rib/core/last_value'`
Save the last result in `Rib.last_value` and the last exception in
`Rib.last_exception`.
#### List of more plugins
``` ruby
require 'rib/more' # You get all of the followings:
```
* `require 'rib/more/multiline_history_file'`
Not only readline could have multiline history, but also the history file.
* `require 'rib/more/bottomup_backtrace'`
Show backtrace bottom-up instead of the regular top-down.
* `require 'rib/more/color'`
Class based colorizing.
* `require 'rib/more/multiline_history'`
Make readline aware of multiline history.
* `require 'rib/more/beep'`
Print "\a" when the application was loaded and it's been too long.
Configure the threshold via `Rib.config[:beep_threshold]`.
* `require 'rib/more/anchor'`
See _As a debugging/interacting tool_.
* `require 'rib/more/caller'`
See _Current call stack (backtrace, caller)_.
* `require 'rib/more/edit'`
See _In place editing_.
### List of extra plugins
There's no `require 'rib/extra'` for extra plugins because they might not
be doing what you would expect or want, or having an external dependency,
or having conflicted semantics.
* `require 'rib/extra/autoindent'` This plugin is depending on:
1. [readline_buffer][]
2. readline plugin
3. multiline plugin
Which would autoindent your input.
* `require 'rib/extra/hirb'` This plugin is depending on:
1. [hirb][]
Which would print the result with hirb.
* `require 'rib/extra/paging'` This plugin is depending on `less` and `tput`.
Which would pass the result to `less` (or `$PAGER` if set) if
the result string is longer than the screen.
* `require 'rib/extra/spring'` in your `~/.spring.rb`
for [Rails Spring](https://github.com/rails/spring) support.
[readline_buffer]: https://github.com/godfat/readline_buffer
[hirb]: https://github.com/cldwalker/hirb
### As a debugging/interacting tool
Rib could be used as a kind of debugging tool which you can set break point
in the source program.
``` ruby
require 'rib/config' # This would load your Rib config
require 'rib/more/anchor'
# If you enabled anchor in config, then needed not
Rib.anchor binding # This would give you an interactive shell
# when your program has been executed here.
Rib.anchor 123 # You can also anchor on an object.
```
But this might be called in a loop, you might only want to
enter the shell under certain circumstance, then you'll do:
``` ruby
require 'rib/debug'
Rib.enable_anchor do
# Only `Rib.anchor` called in the block would launch a shell
end
Rib.anchor binding # No effect (no-op) outside the block
```
Anchor could also be nested. The level would be shown on the prompt,
starting from 1.
### Current call stack (backtrace, caller)
Often time we would want to see current call stack whenever we're using
`Rib.anchor`. We could do that by simply using `caller` but it's barely
readable because it's just returning an array without any format and
it also contains backtrace from Rib itself. You could use pretty
formatting with Rib:
``` ruby
require 'rib/more/caller'
Rib.caller
```
It would use the same format for exception backtrace to show current
call stack for you. Colors, bottom up order, etc, if you're also using
the corresponding plugins.
Sometimes there are also too many stack frames which we don't care about.
In this case, we could pass arguments to `Rib.caller` in order to filter
against them. You could either pass:
* A `String` represents the name of the gem you don't care
* A `Regexp` which would be used to match against paths/methods you don't care
Examples:
``` ruby
require 'rib/more/caller'
Rib.caller 'activesupport', /rspec/
```
To remove backtrace from gem _activesupport_ and paths or methods containing
rspec as part of the name, like things for _rspec_ or _rspec-core_ and so on.
Note that if a method name also contains rspec then it would also be filtered.
Just keep that in mind when using regular expression.
Or if you don't care about any gems, only want to see application related
calls, then try to match against `%r{/gems/}` because gems are often stored
in a path containing `/gems/`:
```
Rib.caller %r{/gem/}
```
Happy debugging.
### In place editing
Whenever you called:
``` ruby
require 'rib/more/edit'
Rib.edit
```
Rib would open an editor according to `$EDITOR` (`ENV['EDITOR']`) for you.
By default it would pick vim if no `$EDITOR` was set. After save and leave
the editor, Rib would evaluate what you had input. This also works inside
an anchor. To use it, require either rib/more/edit or rib/more or rib/all.
### As a shell framework
The essence is:
``` ruby
require 'rib'
```
All others are optional. The core plugins are lying in `rib/core/*.rb`, and
more plugins are lying in `rib/more/*.rb`. You can read `rib/app/rack.rb`
and `bin/rib-rack` as a Rib App reference implementation, because it's very
simple, simpler than rib-rails.
## Other plugins and apps
* [rest-more][] `rib rest-core` Run as interactive rest-core client
* [rib-heroku][] `rib heroku` Run console on Heroku Cedar with your config
[rest-more]: https://github.com/cardinalblue/rest-more
[rib-heroku]: https://github.com/godfat/rib-heroku
## CONTRIBUTORS:
* Andrew Liu (@eggegg)
* ayaya (@ayamomiji)
* Lin Jen-Shin (@godfat)
* Mr. Big Cat (@miaout17)
* @alpaca-tc
* @bootleq
* @lulalala
* @MITSUBOSH
* @tka
## LICENSE:
Apache License 2.0 (Apache-2.0)
Copyright (c) 2011-2026, Lin Jen-Shin (godfat)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
<https://www.apache.org/licenses/LICENSE-2.0>
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Rakefile
================================================
begin
require "#{__dir__}/task/gemgem"
rescue LoadError
sh 'git submodule update --init --recursive'
exec Gem.ruby, '-S', $PROGRAM_NAME, *ARGV
end
Gemgem.init(__dir__) do |s|
require 'rib/version'
s.name = 'rib'
s.version = Rib::VERSION
%w[screenshot.png asciicast.json].each do |file|
s.files.delete(file)
end
end
================================================
FILE: TODO.md
================================================
# TODO
* cleanup the tests. it's so messy right now
* Runner tests
* Documentation
* Implement exception_spy
<https://github.com/godfat/rib/commit/7a97441afeecae80f5493f4e8a4a6ba3044e2c33>
So here we have a problem. Some plugins are expecting to override
some other plugins. The order can't really be arbitrary.....
Actually, users won't care about order either. We just want to
enable/disable plugins, not really composability.
So it really should be a bucket of plugins. At least for built-in plugins,
so that we would be aware of the order. Users shouldn't pay attention
on the order of built-in plugins.
================================================
FILE: asciicast.json
================================================
{
"version": 1,
"width": 80,
"height": 24,
"duration": 31.5,
"command": null,
"title": "rib",
"env": {
"TERM": "xterm-256color",
"SHELL": "/usr/local/bin/fish"
},
"stdout": [
[
0.05,
">> "
],
[
0.05,
"{"
],
[
0.05,
"a"
],
[
0.05,
":"
],
[
0.05,
"0"
],
[
0.05,
","
],
[
0.05,
"'"
],
[
0.05,
"b"
],
[
0.05,
"'"
],
[
0.05,
"="
],
[
0.05,
">"
],
[
0.05,
"["
],
[
0.05,
"O"
],
[
0.05,
"b"
],
[
0.05,
"j"
],
[
0.05,
"e"
],
[
0.05,
"c"
],
[
0.05,
"t"
],
[
0.05,
"]"
],
[
0.05,
","
],
[
0.05,
"n"
],
[
0.05,
"i"
],
[
0.05,
"l"
],
[
0.05,
"="
],
[
0.05,
">"
],
[
0.05,
"t"
],
[
0.05,
"r"
],
[
0.05,
"u"
],
[
0.05,
"e"
],
[
0.05,
"}"
],
[
0.05,
"\r\n"
],
[
0.05,
"=> \u001b[34m{\u001b[0m\u001b[36m:a\u001b[0m\u001b[34m=>\u001b[0m\u001b[31m0\u001b[0m\u001b[34m, \u001b[0m\u001b[32m\"b\"\u001b[0m\u001b[34m=>\u001b[0m\u001b[34m[\u001b[0m\u001b[33mObject\u001b[0m\u001b[34m]\u001b[0m\u001b[34m, \u001b[0m\u001b[35mnil\u001b[0m\u001b[34m=>\u001b[0m\u001b[35mtrue\u001b[0m\u001b[34m}\u001b[0m\r\n"
],
[
0.05,
">> "
],
[
1.5,
"R"
],
[
0.05,
"i"
],
[
0.05,
"b"
],
[
0.05,
"."
],
[
0.05,
"a"
],
[
0.05,
"n"
],
[
0.05,
"c"
],
[
0.05,
"h"
],
[
0.05,
"o"
],
[
0.05,
"r"
],
[
0.05,
" "
],
[
0.05,
"'"
],
[
0.05,
"r"
],
[
0.05,
"o"
],
[
0.05,
"c"
],
[
0.05,
"k"
],
[
0.05,
"'"
],
[
0.05,
"\r\n"
],
[
0.05,
"\u001b[32m\"rock\"\u001b[0m(1)>> "
],
[
1.5,
"u"
],
[
0.05,
"p"
],
[
0.05,
"c"
],
[
0.05,
"a"
],
[
0.05,
"s"
],
[
0.05,
"e"
],
[
0.05,
"\r\n"
],
[
0.05,
"=> \u001b[32m\"ROCK\"\u001b[0m\r\n"
],
[
0.05,
"\u001b[32m\"rock\"\u001b[0m(1)>> "
],
[
1.5,
"R"
],
[
0.05,
"i"
],
[
0.05,
"b"
],
[
0.05,
"."
],
[
0.05,
"a"
],
[
0.05,
"n"
],
[
0.05,
"c"
],
[
0.05,
"h"
],
[
0.05,
"o"
],
[
0.05,
"r"
],
[
0.05,
" "
],
[
0.05,
"s"
],
[
0.05,
"i"
],
[
0.05,
"z"
],
[
0.05,
"e"
],
[
0.05,
"\r\n"
],
[
0.05,
"\u001b[31m4\u001b[0m(2)>> "
],
[
1.5,
"s"
],
[
0.05,
"e"
],
[
0.05,
"l"
],
[
0.05,
"f"
],
[
0.05,
" "
],
[
0.05,
"+"
],
[
0.05,
" "
],
[
0.05,
"1"
],
[
0.05,
"\r\n"
],
[
0.05,
"=> \u001b[31m5\u001b[0m\r\n"
],
[
0.05,
"\u001b[31m4\u001b[0m(2)>> "
],
[
1.5,
"R"
],
[
0.05,
"i"
],
[
0.05,
"b"
],
[
0.05,
"."
],
[
0.05,
"a"
],
[
0.05,
"n"
],
[
0.05,
"c"
],
[
0.05,
"h"
],
[
0.05,
"o"
],
[
0.05,
"r"
],
[
0.05,
" "
],
[
0.05,
"s"
],
[
0.05,
"e"
],
[
0.05,
"l"
],
[
0.05,
"f"
],
[
0.05,
"."
],
[
0.05,
"c"
],
[
0.05,
"l"
],
[
0.05,
"a"
],
[
0.05,
"s"
],
[
0.05,
"s"
],
[
0.05,
"\r\n"
],
[
0.05,
"\u001b[33mInteger\u001b[0m(3)>> "
],
[
1.5,
"e"
],
[
0.05,
"x"
],
[
0.05,
"i"
],
[
0.05,
"t"
],
[
0.05,
"\r\n"
],
[
0.05,
"\u001b[31m4\u001b[0m(2)>> "
],
[
1.5,
"e"
],
[
0.05,
"x"
],
[
0.05,
"i"
],
[
0.05,
"t"
],
[
0.05,
"\r\n"
],
[
0.05,
"\u001b[32m\"rock\"\u001b[0m(1)>> "
],
[
1.5,
"d"
],
[
0.05,
"e"
],
[
0.05,
"f"
],
[
0.05,
" "
],
[
0.05,
"g"
],
[
0.05,
"\r\n"
],
[
0.05,
"\u001b[32m\"rock\"\u001b[0m(1) | "
],
[
0.05,
" "
],
[
0.5,
"a"
],
[
0.05,
" "
],
[
0.05,
"="
],
[
0.05,
" "
],
[
0.05,
"1"
],
[
0.05,
"\r\n"
],
[
0.05,
"\u001b[32m\"rock\"\u001b[0m(1) | "
],
[
0.05,
" "
],
[
0.5,
"R"
],
[
0.05,
"i"
],
[
0.05,
"b"
],
[
0.05,
"."
],
[
0.05,
"a"
],
[
0.05,
"n"
],
[
0.05,
"c"
],
[
0.05,
"h"
],
[
0.05,
"o"
],
[
0.05,
"r"
],
[
0.05,
" "
],
[
0.05,
"b"
],
[
0.05,
"i"
],
[
0.05,
"n"
],
[
0.05,
"d"
],
[
0.05,
"i"
],
[
0.05,
"n"
],
[
0.05,
"g"
],
[
0.05,
"\r\n"
],
[
0.05,
"\u001b[32m\"rock\"\u001b[0m(1) | "
],
[
0.05,
" "
],
[
0.5,
"e"
],
[
0.05,
"n"
],
[
0.05,
"d"
],
[
0.05,
"\r\n"
],
[
0.05,
"\u001b[1A\u001b[K\u001b[32m\"rock\"\u001b[0m(1) | end\r\n"
],
[
0.05,
"=> \u001b[36m:g\u001b[0m\r\n"
],
[
0.05,
"\u001b[32m\"rock\"\u001b[0m(1)>> "
],
[
1.5,
"a"
],
[
0.05,
"\r\n"
],
[
0.05,
" \u001b[33m\u001b[33m\u001b[33m(rib)\u001b[0m\u001b[0m\u001b[0m:\u001b[31m2\u001b[0m:in \u001b[32m\u001b[32m\u001b[32m`main'\u001b[0m\u001b[0m\u001b[0m\r\n"
],
[
0.05,
"\u001b[35mNameError: undefined local variable or method `a' for \"rock\":String\u001b[0m\r\n"
],
[
0.05,
"\u001b[32m\"rock\"\u001b[0m(1)>> "
],
[
1.5,
"g"
],
[
0.05,
"\r\n"
],
[
0.05,
"\u001b[33m\"rock\"\u001b[0m(2)>> "
],
[
1.5,
"a"
],
[
0.05,
"\r\n"
],
[
0.05,
"=> \u001b[31m1\u001b[0m\r\n"
],
[
0.05,
"\u001b[33m\"rock\"\u001b[0m(2)>> "
],
[
1.5,
"e"
],
[
0.05,
"x"
],
[
0.05,
"i"
],
[
0.05,
"t"
],
[
0.05,
"\r\n"
],
[
0.05,
"\u001b[32m\"rock\"\u001b[0m(1)>> "
],
[
1.5,
"e"
],
[
0.05,
"x"
],
[
0.05,
"i"
],
[
0.05,
"t"
],
[
0.05,
"\r\n"
],
[
0.05,
">> "
],
[
1.5,
"e"
],
[
0.05,
"x"
],
[
0.05,
"i"
],
[
0.05,
"t"
],
[
0.05,
"\r\n"
]
]
}
================================================
FILE: bin/rib
================================================
#!/usr/bin/env ruby
require 'rib/runner'
Rib.config[:mimic_irb] = true
Rib::Runner.run(ARGV)
================================================
FILE: bin/rib-all
================================================
#!/usr/bin/env ruby
require 'rib/runner'
require 'rib/all'
Rib::Runner.run(ARGV)
================================================
FILE: bin/rib-auto
================================================
#!/usr/bin/env ruby
require 'rib/runner'
# create the shell before app to prvent your bundler (if any) kicks in
Rib.shell
# we need to require anything before loading the app,
# and both `rib auto` (true) and `rib-auto` (nil) should work
require 'rib/core' if Rib.config.delete(:mimic_irb) != false
require 'rib/app/auto'
# load the app
Rib::Auto.load
Rib::Runner.run(ARGV)
================================================
FILE: bin/rib-min
================================================
#!/usr/bin/env ruby
require 'rib/runner'
Rib.config[:mimic_irb] = false
Rib::Runner.run(ARGV)
================================================
FILE: bin/rib-rack
================================================
#!/usr/bin/env ruby
require 'rib/runner'
# create the shell before app to prvent your bundler (if any) kicks in
Rib.shell
# we need to require anything before loading the app,
# and both `rib auto` (true) and `rib-auto` (nil) should work
require 'rib/core' if Rib.config.delete(:mimic_irb) != false
require 'rib/app/rack'
# load the app
Rib::Rack.load
Rib::Runner.run(ARGV)
================================================
FILE: bin/rib-rails
================================================
#!/usr/bin/env ruby
require 'rib/runner'
# create the shell before app to prvent your bundler (if any) kicks in
Rib.shell
# we need to require anything before loading the app,
# and both `rib auto` (true) and `rib-auto` (nil) should work
require 'rib/core' if Rib.config.delete(:mimic_irb) != false
require 'rib/app/rails'
# load the app
Rib::Rails.load
Rib::Runner.run(ARGV)
================================================
FILE: lib/rib/all.rb
================================================
# frozen_string_literal: true
require 'rib/core'
require 'rib/more'
================================================
FILE: lib/rib/api.rb
================================================
# frozen_string_literal: true
module Rib; module API
# Called before shell starts looping
def before_loop
self
end
# Called after shell finishes looping
def after_loop
self
end
# Handle interrupt (control-c)
def handle_interrupt; puts ; end
# The prompt string of this shell
def prompt ; config[:prompt] ; end
# The result prompt string of this shell
def result_prompt; config[:result_prompt] ; end
# The name of this shell
def name ; config[:name] ; end
# The binding for evaluation
def eval_binding ; config[:binding] ; end
# The line number for next evaluation
def line ; config[:line] ; end
# When the application loaded
def started_at ; config[:started_at] ; end
# Main loop
def in_loop
input = catch(:rib_exit){ loop_once while running? }
puts if input == nil && running?
end
# Loop iteration: REPL
def loop_once
input, result, err = get_input, nil, nil
throw(:rib_exit, input) if config[:exit].include?(input)
result, err = eval_input(input)
if err
print_eval_error(err)
elsif input.strip != '' && !equal_rib_skip(result)
print_result(result)
else
# print nothing for blank input or Rib::Skip
end
flush_warnings
[result, err]
rescue Interrupt
handle_interrupt
end
# Get user input. This is most likely overrided in Readline plugin
def get_input
print(prompt)
if input = $stdin.gets
input.chomp
else
nil
end
end
# Evaluate the input using #loop_eval and handle it
def eval_input input
[loop_eval(input), nil]
rescue SystemExit
throw(:rib_exit, input)
rescue Exception => e
[nil, e]
ensure
config[:line] += 1
end
# Evaluate user input with #eval_binding, name and line
def loop_eval input
if eval_binding.kind_of?(Binding)
eval_binding.eval(input, "(#{name})", line)
else
eval_binding.instance_eval(input, "(#{name})", line)
end
end
def puts str=''
super
end
# Print result using #format_result
def print_result result
puts(format_result(result))
rescue StandardError, SyntaxError => e
warn("Error while printing result:\n #{format_error(e)}")
end
# Print evaluated error using #format_error
def print_eval_error err
puts(format_error(err))
rescue StandardError, SyntaxError => e
warn("Error while printing error:\n #{format_error(e)}")
end
def warn message
warnings << message
end
# Format result using #result_prompt
def format_result result
"#{result_prompt}#{inspect_result(result)}"
end
def inspect_result result
string = result.inspect
warn("#{result.class}#inspect is not returning a string") unless
string.kind_of?(String)
string
end
# Format error raised in #loop_eval with #get_error
def format_error err
message, backtrace = get_error(err)
"#{message}\n #{backtrace.join("\n ")}"
end
module_function :format_error
# Get error message and backtrace from a particular error
def get_error err
["#{err.class}: #{err.message}", format_backtrace(err.backtrace)]
end
module_function :get_error
def format_backtrace backtrace
backtrace
end
private
def equal_rib_skip result
result == Rib::Skip
rescue
# do nothing, it cannot respond to == correctly, it can't be Rib::Skip
end
def flush_warnings
Rib.warn(warnings.shift) until warnings.empty?
end
end; end
================================================
FILE: lib/rib/app/auto.rb
================================================
# frozen_string_literal: true
module Rib; module Auto
module_function
def load
app, name = %w[rails rack].find{ |n|
require "rib/app/#{n}"
a = Rib.const_get(n.capitalize)
break a, n if a.public_send("#{n}?")
}
if app
Rib.say("Found #{name.capitalize}, loading it...")
begin
app.load
rescue LoadError => e
Rib.warn("Error: #{e}", "Is this a #{app} app?")
end
else
Rib.warn("No app found")
end
end
end; end
================================================
FILE: lib/rib/app/rack.rb
================================================
# frozen_string_literal: true
module Rib; module Rack
singleton_class.module_eval{ attr_accessor :app }
module_function
def load
load_rack
rescue LoadError => e
Rib.abort("Error: #{e}", "Is this a Rack app?")
end
def load_rack
require 'rack'
Rib.abort("Error: Cannot find config.ru") unless rack?
app, _ = ::Rack::Builder.parse_file(configru_path)
self.app = app
Rib.shell.eval_binding.eval('def app; Rib::Rack.app; end')
Rib.say("Access your app via :app method")
end
def rack?
File.exist?(configru_path)
end
def configru_path
"#{Rib.config[:prefix]}/config.ru"
end
end; end
================================================
FILE: lib/rib/app/rails.rb
================================================
# frozen_string_literal: true
module Rib; module Rails
module_function
def load
load_rails
rescue LoadError => e
Rib.abort("Error: #{e}", "Is this a Rails app?")
end
def load_rails
require path_for('boot')
if File.exist?(path_for('application.rb'))
Rib::Rails.load_rails3
else
Rib::Rails.load_rails2
end
end
def load_rails2
optparse_env
Rib.silence{
# rails 2 is so badly written
require 'stringio'
stderr = $stderr
$stderr = StringIO.new
Object.const_set('RAILS_ENV', ENV['RAILS_ENV'] || 'development')
$stderr = stderr
}
# copied from commands/console
[path_for('environment'),
'console_app',
'console_with_helpers'].each{ |f| require f }
optparse_rails
end
def load_rails3
optparse_env
# copied from rails/commands
require path_for('application')
::Rails.application.require_environment!
optparse_rails
end
# copied from rails/commands/console
def optparse_env
# Has to set the RAILS_ENV before config/application is required
if ARGV.first && !ARGV.first.index("-") && env = ARGV.shift # has to shift the env ARGV so IRB doesn't freak
ENV['RAILS_ENV'] = %w(production development test).detect {|e| e =~ /^#{env}/} || env
end
end
# copied from rails/commands/console
def optparse_rails
require 'optparse'
options = {}
OptionParser.new do |opt|
opt.banner = "Usage: rib rails [environment] [options]"
opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |v| options[:sandbox] = v }
opt.on("--debugger", 'Enable ruby-debugging for the console.') { |v| options[:debugger] = v }
opt.parse!(ARGV)
end
# rails 3
if ::Rails.respond_to?(:application) && (app = ::Rails.application)
# rails 3.1
if app.respond_to?(:sandbox)
app.sandbox = options[:sandbox]
app.load_console
# rails 3.0
else
app.load_console(options[:sandbox])
end
else
# rails 2
require 'console_sandbox' if options[:sandbox]
end
if options[:debugger]
begin
require 'ruby-debug'
puts "=> Debugger enabled"
rescue Exception
puts "You need to install ruby-debug to run the console in debugging mode. With gems, use 'gem install ruby-debug'"
exit
end
end
if options[:sandbox]
puts "Loading #{::Rails.env} environment in sandbox (Rails #{::Rails.version})"
puts "Any modifications you make will be rolled back on exit"
else
puts "Loading #{::Rails.env} environment (Rails #{::Rails.version})"
end
# rails 3.2
if ::Rails.const_defined?(:ConsoleMethods)
Rib.shell.eval_binding.eval('extend ::Rails::ConsoleMethods')
end
end
def rails?
File.exist?(path_for('boot.rb')) &&
File.exist?(path_for('environment.rb'))
end
def path_for file
File.expand_path("#{Rib.config[:prefix]}/config/#{file}")
end
end; end
================================================
FILE: lib/rib/config.rb
================================================
# frozen_string_literal: true
require 'rib'
Rib.require_config
================================================
FILE: lib/rib/core/completion.rb
================================================
# frozen_string_literal: true
require 'rib'
module Rib; module Completion
extend Plugin
Shell.use(self)
# --------------- Rib API ---------------
def before_loop
return super if Completion.disabled?
config[:completion] ||= {}
config[:completion][:gems] ||= []
config[:completion][:eval_binding] ||= method(:eval_binding).to_proc
Rib.silence{Bond.start(config[:completion]) unless Bond.started?}
super
end
end; end
begin
Rib.silence{require 'bond'}
rescue LoadError => e
Rib.warn("Error: #{e}" ,
"Please install bond to use completion plugin:\n",
" gem install bond\n" ,
"Or add bond to Gemfile if that's the case" )
Rib::Completion.disable
end
================================================
FILE: lib/rib/core/history.rb
================================================
# frozen_string_literal: true
require 'rib'
require 'fileutils'
module Rib; module History
extend Plugin
Shell.use(self)
# --------------- Rib API ---------------
def before_loop
return super if History.disabled?
history_file
history_size
FileUtils.mkdir_p(File.dirname(history_file_path))
read_history
Rib.say("History read from: #{history_file_path}") if $VERBOSE
super
end
def after_loop
return super if History.disabled?
write_history
Rib.say("History wrote to: #{history_file_path}") if $VERBOSE
super
end
def get_input
return super if History.disabled?
(history << super).last
end
# --------------- Plugin API ---------------
# The history data
def history; config[:history] ||= []; end
# Read config[:history_file] into #history, handled in history_file plugin
def read_history
return super if History.disabled?
File.exist?(history_file_path) && history.empty? &&
File.readlines(history_file_path).each{ |e| history << e.chomp }
end
# Write #history into config[:history_file], handled in history_file plugin
def write_history
return super if History.disabled?
history_text = "#{history.to_a.last(history_size).join("\n")}\n"
File.write(history_file_path, history_text)
end
private
def history_file
config[:history_file] ||= File.join(Rib.home, 'history.rb')
end
def history_file_path
config[:history_file_path] ||= File.expand_path(history_file)
end
def history_size
config[:history_size] ||= 500
end
end; end
================================================
FILE: lib/rib/core/last_value.rb
================================================
# frozen_string_literal: true
require 'rib'
module Rib; module LastValue
extend Plugin
Shell.use(self)
attr_reader :last_value, :last_exception
def print_result result
return super if LastValue.disabled?
@last_value = result
super
end
def print_eval_error err
return super if LastValue.disabled?
@last_exception = err
super
end
module Imp
def last_value
Rib.shell.last_value
end
def last_exception
Rib.shell.last_exception
end
end
Rib.extend(Imp)
end; end
================================================
FILE: lib/rib/core/multiline.rb
================================================
# frozen_string_literal: true
require 'rib'
# from https://github.com/janlelis/ripl-multi_line
module Rib; module Multiline
extend Plugin
Shell.use(self)
engine = if Object.const_defined?(:RUBY_ENGINE)
RUBY_ENGINE
else
'ruby'
end
# test those:
# ruby -e '"'
# ruby -e '{'
# ruby -e '['
# ruby -e '('
# ruby -e '/'
# ruby -e 'class C'
# ruby -e 'def f'
# ruby -e 'begin'
# ruby -e 'case 1'
# ruby -e 'eval "1+1.to_i +"'
# ruby -e 'eval "1+1.to_i -"'
# ruby -e 'eval "1+1.to_i *"'
# ruby -e 'eval "1+1.to_i /"'
# ruby -e 'eval "1+1.to_i &"'
# ruby -e 'eval "1+1.to_i |"'
# ruby -e 'eval "1+1.to_i ^"'
BINARY_OP = %w[tUPLUS tUMINUS tSTAR tREGEXP_BEG tAMPER]
RUBY20_IO = %w[unary+ unary- * tREGEXP_BEG &].
map(&Regexp.method(:escape))
ERROR_REGEXP = case engine
when 'ruby' ; Regexp.new(
[ # string or regexp
"unterminated \\w+ meets end of file",
# mri and rubinius
"unexpected (#{BINARY_OP.join('|')}), expecting \\$end",
"syntax error, unexpected \\$end" ,
# prism
"expected an? `.+?` to close the",
"expected a matching `\\)`",
# ruby 2.0 and prism
"unexpected end-of-input",
# ruby 2.0
"syntax error, unexpected (#{RUBY20_IO.join('|')}),"
].join('|'))
when 'rbx' ; Regexp.new(
[ # string or regexp
"unterminated \\w+ meets end of file",
# mri and rubinius
"syntax error, unexpected \\$end" ,
# rubinius
"expecting keyword_end" ,
"expecting keyword_then" ,
"expecting keyword_when" ,
"expecting keyword_do_cond" ,
"expecting \\$end" ,
"expecting '.+'( or '.+')*" ,
"missing '.+' for '.+' started on line \\d+"].join('|'))
when 'jruby'; Regexp.new(
[ # string or regexp
"unterminated \\w+ meets end of file",
# jruby
"syntax error, unexpected end\\-of\\-file",
# jruby 9.0.4.0
"formal argument must be local variable",
# jruby 9.2.0.0
"syntax error, unexpected (#{RUBY20_IO.join('|')})",
"syntax error, unexpected '\\W'"
].join('|'))
end
# --------------- Rib API ---------------
def loop_once
return super if Multiline.disabled?
result = nil
catch(:rib_multiline) do
result = super
multiline_buffer.clear
end
result
end
def loop_eval input
return super if Multiline.disabled?
multiline_buffer << input
if input =~ /\\\z/
throw :rib_multiline
else
super(multiline_buffer.join("\n"))
end
end
def print_eval_error err
return super if Multiline.disabled?
if multiline?(err)
throw :rib_multiline
else
super
end
end
def prompt
return super if Multiline.disabled?
if multiline_buffer.empty?
super
else
mprompt = multiline_prompt[0, config[:prompt].size]
"#{' '*(config[:prompt].size-mprompt.size)}#{mprompt}"
end
end
def handle_interrupt
return super if Multiline.disabled?
if multiline_buffer.empty?
super
else
print "[removed this line: #{multiline_buffer.pop}]"
super
throw :rib_multiline
end
end
# --------------- Plugin API ---------------
def multiline? err
err.is_a?(SyntaxError) && err.message =~ ERROR_REGEXP
end
def multiline_prompt
config[:multiline_prompt] ||= '| '
end
private
def multiline_buffer
@multiline_buffer ||= []
end
end; end
================================================
FILE: lib/rib/core/readline.rb
================================================
# frozen_string_literal: true
require 'rib'
require 'readline'
module Rib; module Readline
extend Plugin
Shell.use(self)
# --------------- Rib API ---------------
def before_loop
return super if Readline.disabled?
config[:history] = ::Readline::HISTORY
super
end
def get_input
return super if Readline.disabled?
::Readline.readline(prompt, true)
end
end
unless ::Readline::HISTORY.respond_to?(:last)
def (::Readline::HISTORY).last
self[-1]
end
end; end
================================================
FILE: lib/rib/core/squeeze_history.rb
================================================
# frozen_string_literal: true
require 'rib/core/history' # dependency
module Rib; module SqueezeHistory
extend Plugin
Shell.use(self)
# --------------- Rib API ---------------
# squeeze history in memory too
def loop_once
return super if SqueezeHistory.disabled?
begin
input, last_input = history[-1], history[-2]
rescue IndexError # EditLine is really broken, to_a is needed for it
array = history.to_a
input, last_input = array[-1], array[-2]
end
history.pop if input.to_s.strip == '' ||
(history.size > 1 && input == last_input)
super
end
# --------------- Plugin API ---------------
# write squeezed history
def write_history
return super if SqueezeHistory.disabled?
config[:history] = squeezed_history
super
end
private
def squeezed_history
history.to_a.inject([]){ |result, item|
if result.last == item || item.strip == ''
result
else
result << item
end
}
end
end; end
================================================
FILE: lib/rib/core/strip_backtrace.rb
================================================
# frozen_string_literal: true
require 'rib'
module Rib; module StripBacktrace
extend Plugin
Shell.use(self)
# --------------- Rib API ---------------
def format_error err
return super if StripBacktrace.disabled?
message, backtrace = get_error(err)
"#{message}\n #{backtrace.join("\n ")}"
end
def get_error err
return super if StripBacktrace.disabled?
["#{err.class}: #{err.message}", format_backtrace(err.backtrace)]
end
module_function
def format_backtrace backtrace
return super if StripBacktrace.disabled?
strip_home_backtrace(
strip_cwd_backtrace(
strip_rib_backtrace(super(backtrace))))
end
def strip_home_backtrace backtrace
backtrace.map(&method(:replace_path_prefix).curry[ENV['HOME'], '~/'])
end
def strip_cwd_backtrace backtrace
backtrace.map(&method(:replace_path_prefix).curry[Dir.pwd, ''])
end
def strip_rib_backtrace backtrace
backtrace[
0..backtrace.rindex{ |l| l =~ /\(#{name}\):\d+:in (?:`|').+?'/ } || -1]
end
def replace_path_prefix prefix, substitute, path
path.sub(/\A#{Regexp.escape(prefix)}\//, substitute)
end
end; end
================================================
FILE: lib/rib/core.rb
================================================
# frozen_string_literal: true
# before session starts
require 'rib/core/completion'
# upon session ends
require 'rib/core/history'
# upon formatting output
require 'rib/core/strip_backtrace'
# upon input
require 'rib/core/readline'
require 'rib/core/multiline'
require 'rib/core/squeeze_history'
# special tools
require 'rib/core/last_value'
================================================
FILE: lib/rib/debug.rb
================================================
# frozen_string_literal: true
require 'rib/config'
require 'rib/more/anchor'
Rib::Anchor.disable
Rib::Debugger.disable if Rib.const_defined?(:Debugger)
================================================
FILE: lib/rib/extra/autoindent.rb
================================================
# frozen_string_literal: true
require 'rib/core/history' # otherwise the order might be wrong
require 'rib/core/readline' # dependency
require 'rib/core/multiline' # dependency
module Rib; module Autoindent
extend Plugin
Shell.use(self)
# begin block could be simpler, because it should also trigger
# SyntaxError, otherwise indention would be wiped out.
# but end block should be exactly match, because we don't have
# SyntaxError information, also triggering SyntaxError doesn't
# mean it's not an end block, thinking about nested multiline!
BLOCK_REGEXP = {
# rescue Expression? (=> VariableName)?
# consider cases:
# rescue
# rescue=>e
# rescue => e
# rescue =>e
# rescue E=>e
# rescue E
# rescue E => e
# rescue E=> e
# rescue E =>e
# ensure
/^begin$/ =>
/^(end)\b|^else$|^rescue *((\w+)? *(=> *\w+)?)?$|^ensure$/,
/^def\b/ =>
/^(end)\b|^else$|^rescue *((\w+)? *(=> *\w+)?)?$|^ensure$/,
# elsif Expression
# consider cases:
# elsif(true)
# elsif true
# elsif true == true
# elsif (a = true) && false
/^if\b/ => /^(end)\b|^else$|^elsif\b/,
/^unless\b/ => /^(end)\b|^else$|^elsif\b/,
/^case\b/ => /^(end)\b|^else$|when\b/ ,
/^class\b/ => /^(end)\b/ ,
/^module\b/ => /^(end)\b/ ,
/^while\b/ => /^(end)\b/ ,
/^for\b/ => /^(end)\b/ ,
/^until\b/ => /^(end)\b/ ,
# consider cases:
# 'do
# ' do
# "' do
# /do
# '{
# %q{
# %q| do
# hey, two lines are even harder!
# "
# begin
/do( *\|.*\|)?$/ => /^(end)\b/ ,
/\{( *\|.*\|)?$/ => /^(\})\B/ ,
/\($/ => /^(\))\B/ ,
/\[$/ => /^(\])\B/ ,
# those are too hard to deal with, so we use syntax error to double check
# what about this then?
# v = if true
# else
# end
}
# --------------- Rib API ---------------
def before_loop
return super if Autoindent.disabled?
autoindent_spaces
super
end
def get_input
return super if Autoindent.disabled?
# this is only a fix in case we don't autoindent correctly
# if we're autoindenting 100% correct, then this is a useless check
autoindent_stack.clear if multiline_buffer.empty?
# this should be called after ::Readline.readline, but it's blocking,
# and i don't know if there's any hook to do this, so here we use thread
Thread.new do
sleep(0.01)
::Readline.line_buffer = current_autoindent if
::Readline.line_buffer && ::Readline.line_buffer.empty?
end
super
end
def eval_input raw_input
return super if Autoindent.disabled?
input = raw_input.strip
indent = detect_autoindent(input)
result, err = super
handle_autoindent(input, indent, err)
[result, err]
end
# --------------- Plugin API ---------------
def detect_autoindent input
_, backmark = BLOCK_REGEXP.find{ |key, _| input =~ key }
if backmark # e.g. begin
[:right, backmark]
elsif input =~ autoindent_stack.last
if $1 # e.g. end, }, etc
[:left_end]
else # e.g. elsif, rescue, etc
[:left_tmp]
end
else
[:stay]
end
end
def handle_autoindent input, indent, err
case indent.first
when :right # we need to go deeper
if multiline?(err)
if err.message =~ /unterminated \w+ meets end of file/
# skip if we're in the middle of a string or regexp
else
# indent.last is the way (input regexp matches) to go back
autoindent_stack << indent.last
end
end
when :left_end # we need to go back
# could happen in either multiline or not
handle_last_line(input)
autoindent_stack.pop
when :left_tmp # temporarily go back
handle_last_line(input) if multiline?(err)
end
end
def handle_last_line input,
indent=current_autoindent(autoindent_stack.size-1)
new_input = "#{indent}#{input}"
puts("\e[1A\e[K#{prompt}#{new_input}")
new_input
end
private
def current_autoindent size=autoindent_stack.size
autoindent_spaces * size
end
def autoindent_spaces
config[:autoindent_spaces] ||= ' '
end
def autoindent_stack
@autoindent_stack ||= []
end
end; end
begin
require 'readline_buffer'
rescue LoadError => e
Rib.warn("Error: #{e}" ,
"Please install readline_buffer to use autoindent plugin:\n",
" gem install readline_buffer\n" ,
"Or add readline_buffer to Gemfile if that's the case" )
Rib::Autoindent.disable
end
================================================
FILE: lib/rib/extra/byebug.rb
================================================
# frozen_string_literal: true
require 'rib/more/anchor'
require 'byebug/core'
# This is based on lib/byebug/processors/pry_processor.rb
module Rib; module Byebug
extend Plugin
Shell.use(self)
def before_loop
return super if Rib::Byebug.disabled?
super
# ::Byebug::RibProcessor.start
end
module Imp
def byebug
return if Rib::Byebug.disabled?
::Byebug::RibProcessor.start
end
def location
Rib.shell.config[:byebug].location
end
def step times=1
throw :rib_byebug, [:step, times]
end
def next lines=1
throw :rib_byebug, [:next, lines]
end
def finish
throw :rib_byebug, [:finish]
end
end
Rib.extend(Imp)
end; end
module Byebug
class RibProcessor < CommandProcessor
def self.start
Byebug.start
Setting[:autolist] = false
Context.processor = self
steps = caller.index{ |path| !path.start_with?(__FILE__) }
Byebug.current_context.step_out(steps + 2, true)
end
def at_line
resume_rib
end
def at_return(_return_value)
resume_rib
end
def at_end
resume_rib
end
def at_breakpoint(breakpoint)
raise NotImplementedError
end
def location
context.location
end
private
def print_location
shell = Rib.shell
shell.puts(shell.format_backtrace([location]).first)
end
def resume_rib
return if Rib.shell.running?
byebug_binding = frame._binding
print_location
action, *args = catch(:rib_byebug) do
allowing_other_threads do
Rib.anchor byebug_binding, :byebug => self
end
end
perform(action, args)
end
def perform action, args
case action
when :step
context.step_into(*args, frame.pos)
when :next
context.step_over(*args, frame.pos)
when :finish
context.step_out(1)
end
end
end
end
================================================
FILE: lib/rib/extra/hirb.rb
================================================
# frozen_string_literal: true
require 'rib'
module Rib; module Hirb
extend Plugin
Shell.use(self)
# --------------- Rib API ---------------
def format_result result
return super if Hirb.disabled?
::Hirb::View.view_or_page_output(result) || super
end
end
begin
Rib.silence{
require 'hirb'
::Hirb.enable
}
rescue LoadError => e
Rib.warn("Error: #{e}" ,
"Please install hirb to use hirb plugin:\n",
" gem install hirb\n" ,
"Or add hirb to Gemfile if that's the case")
Rib::Hirb.disable
end; end
================================================
FILE: lib/rib/extra/paging.rb
================================================
# frozen_string_literal: true
require 'rib'
module Rib; module Paging
extend Plugin
Shell.use(self)
# --------------- Rib API ---------------
# Print if the it fits one screen, paging it through a pager otherwise.
def puts str=''
return super if Paging.disabled?
if one_screen?(str)
super
else
page_result(str)
end
end
# `less -F` can't cat the output, so we need to detect by ourselves.
# `less -X` would mess up the buffers, so it's not desired, either.
def one_screen? str
cols, lines = `tput cols`.to_i, `tput lines`.to_i
(str.count("\n") + 2) <= lines && # count last line and prompt
str.gsub(/\e\[[^m]*m/, '').size <= cols * lines
end
def page_result str
less = IO.popen(pager, 'w')
less.write(str)
less.close_write
rescue Errno::EPIPE
# less quit without consuming all the input
end
def pager
ENV['PAGER'] || 'less -R'
end
end; end
pager = ENV['PAGER'] || 'less'
if `which #{pager}`.empty?
Rib.warn("#{pager} is not available, disabling Rib::Paging")
Rib::Paging.disable
elsif `which tput`.empty?
Rib.warn("tput is not available, disabling Rib::Paging")
Rib::Paging.disable
elsif ENV['TERM'] == 'dumb' || ENV['TERM'].nil?
Rib.warn("Your terminal is dumb, disabling Rib::Paging")
Rib::Paging.disable
end
================================================
FILE: lib/rib/extra/spring.rb
================================================
# frozen_string_literal: true
module Spring
module Commands
class Rib
def call
load `which rib`.chomp
end
end
Spring.register_command 'rib', Rib.new
end
end
================================================
FILE: lib/rib/more/anchor.rb
================================================
# frozen_string_literal: true
require 'rib'
module Rib; module Anchor
extend Plugin
Shell.use(self)
# --------------- Rib API ---------------
def prompt
return super if Rib::Anchor.disabled?
return super unless anchor?
level = "(#{Rib.shells.size - 1})"
if Rib.const_defined?(:Color) &&
kind_of?(Rib::Color) &&
Rib::Color.enabled?
"#{format_color(eval_binding, prompt_anchor)}#{level}#{super}"
else
"#{prompt_anchor}#{level}#{super}"
end
end
def anchor?
!!config[:prompt_anchor]
end
private
def prompt_anchor
@prompt_anchor ||=
if eval_binding.kind_of?(Binding)
eval_binding.eval('self', __FILE__, __LINE__)
else
eval_binding
end.inspect[0..9]
end
module Imp
# Enter an interactive Rib shell based on a particular context.
#
# @api public
# @param obj_or_binding [Object, Binding] The context of the shell.
# @param opts [Hash] The config hash passed to the newly created shell.
# See {Rib::Shell#initialize} for all possible options.
# @return [Rib::Skip] This is the mark telling Rib do not print anything.
# It's only used internally in Rib.
# @see Rib::Shell#initialize
# @example
# Rib.anchor binding
# Rib.anchor 123
def anchor obj_or_binding, opts={}
return if Rib::Anchor.disabled?
if Rib.shell.running?
Rib.shells << Rib::Shell.new(
Rib.shell.config.merge( :binding => obj_or_binding,
:prompt_anchor => true ).
merge(opts))
else
Rib.shell.config.merge!(:binding => obj_or_binding,
:prompt_anchor => true ).
merge!(opts)
end
Rib.shell.loop
Rib::Skip
ensure
Rib.shells.pop
end
def stop_anchors
Rib.shells.select(&:anchor?).each(&:stop)
Rib::Skip
end
end
Rib.extend(Imp)
end; end
================================================
FILE: lib/rib/more/beep.rb
================================================
# frozen_string_literal: true
require 'rib'
module Rib; module Beep
extend Plugin
Shell.use(self)
# --------------- Rib API ---------------
def loop_once
return super if Beep.disabled?
beep if started_at && (Time.now - started_at) > beep_threshold
config[:started_at] = Time.now
super
end
private
def beep
print "\a"
end
def beep_threshold
config[:beep_threshold] ||= 5
end
end; end
================================================
FILE: lib/rib/more/bottomup_backtrace.rb
================================================
# frozen_string_literal: true
require 'rib'
module Rib; module BottomupBacktrace
extend Plugin
Shell.use(self)
# --------------- Rib API ---------------
def format_error err
return super if BottomupBacktrace.disabled?
message, backtrace = get_error(err)
" #{backtrace.join("\n ")}\n#{message}"
end
def format_backtrace backtrace
super(backtrace).reverse
end
end; end
================================================
FILE: lib/rib/more/caller.rb
================================================
# frozen_string_literal: true
require 'rib'
module Rib; module Caller
extend Plugin
Shell.use(self)
module Imp
def caller *filters
return if Rib::Caller.disabled?
display_backtrace(super().drop(1), *filters)
end
def display_backtrace raw_backtrace, *filters
backtrace = Rib.shell.format_backtrace(raw_backtrace)
lib = %r{\brib-#{Rib::VERSION}/lib/rib/}
if backtrace.first =~ lib
backtrace.shift while backtrace.first =~ lib
elsif backtrace.last =~ lib
backtrace.pop while backtrace.last =~ lib
end
result = filters.map do |f|
case f
when Regexp
f
when String
%r{\bgems/#{Regexp.escape(f)}\-[\d\.]+/lib/}
end
end.inject(backtrace, &:grep_v)
Rib.shell.puts result.map{ |l| " #{l}" }.join("\n")
Rib::Skip
end
end
Rib.extend(Imp)
end; end
================================================
FILE: lib/rib/more/color.rb
================================================
# frozen_string_literal: true
require 'rib'
module Rib; module Color
extend Plugin
Shell.use(self)
# --------------- Rib API ---------------
def before_loop
colors
super
end
def format_result result
return super if Color.disabled?
"#{result_prompt}#{format_color(result)}"
end
def get_error err
return super if Color.disabled?
message, backtrace = super
[format_color(err, message), backtrace]
end
def warn message
return super if Color.disabled?
super(red{message})
end
# --------------- Plugin API ---------------
def colors
config[:color] ||= {
Numeric => :red ,
String => :green ,
Symbol => :cyan ,
Array => :blue ,
Hash => :blue ,
NilClass => :magenta,
TrueClass => :magenta,
FalseClass => :magenta,
Exception => :magenta,
Object => :yellow }
end
def format_color result, display=inspect_result(result)
case result
when String ; send(colors[String ]){ display }
when Numeric; send(colors[Numeric]){ display }
when Symbol ; send(colors[Symbol ]){ display }
when Array ; send(colors[Array ]){ '[' } +
result.map{ |e | if e.object_id == result.object_id
send(colors[Array]){'[...]'}
else
format_color(e); end }.
join(send(colors[Array ]){ ', ' }) +
send(colors[Array ]){ ']' }
when Hash ; send(colors[Hash ]){ '{' } +
result.map{ |k, v| format_color(k) +
send(colors[Hash ]){ '=>' } +
if v.object_id == result.object_id
send(colors[Hash]){'{...}'}
else
format_color(v); end }.
join(send(colors[Hash ]){ ', ' }) +
send(colors[Hash ]){ '}' }
else ; if color = find_color(colors, result)
send(color){ display }
else
send(colors[Object]){ display }
end
end
end
def format_backtrace backtrace
colorize_backtrace(super(backtrace))
end
module_function
def colorize_backtrace backtrace
backtrace.map{ |b|
path, msgs = b.split(':', 2)
dir, sep, file = path.rpartition('/')
msgs ||= (line - 1).to_s # msgs would be nil when input is next/break
msg = msgs.sub(/(\d+)(:?)/) do
m = Regexp.last_match
"#{red{m[1]}}#{m[2]}"
end.sub(/(?:`|').+?'/){green{Regexp.last_match[0]}}
"#{dir+sep}#{yellow{file}}:#{msg}"
}
end
def find_color colors, value
(colors.sort{ |(k1, _), (k2, _)|
# Class <=> Class
if k1 < k2 then -1
elsif k1 > k2 then 1
else 0
end}.find{ |(klass, _)| value.kind_of?(klass) } || []).last
end
def color rgb
"\e[#{rgb}m" + if block_given? then "#{yield}#{reset}" else '' end
end
def black █ color(30, &block); end
def red █ color(31, &block); end
def green █ color(32, &block); end
def yellow █ color(33, &block); end
def blue █ color(34, &block); end
def magenta █ color(35, &block); end
def cyan █ color(36, &block); end
def white █ color(37, &block); end
def reset █ color( 0, &block); end
end; end
begin
require 'win32console' if defined?(Gem) && Gem.win_platform?
rescue LoadError => e
Rib.warn("Error: #{e}" ,
"Please install win32console to use color plugin on Windows:\n",
" gem install win32console\n" ,
"Or add win32console to Gemfile if that's the case" )
Rib::Color.disable
end
================================================
FILE: lib/rib/more/edit.rb
================================================
# frozen_string_literal: true
require 'rib'
require 'tempfile'
module Rib; module Edit
extend Plugin
Shell.use(self)
module Imp
def edit
return if Rib::Edit.disabled?
file = Tempfile.new(['rib.edit', '.rb'])
file.puts(Rib.vars[:edit])
file.close
shell = Rib.shell
system("#{shell.editor} #{file.path}")
if shell.running?
shell.send(:multiline_buffer).pop
else
shell.before_loop
end
shell.loop_eval(Rib.vars[:edit] = File.read(file.path))
ensure
file.close
file.unlink
end
end
def editor
ENV['EDITOR'] || 'vim'
end
Rib.extend(Imp)
end; end
================================================
FILE: lib/rib/more/multiline_history.rb
================================================
# frozen_string_literal: true
require 'rib/core/history' # dependency
require 'rib/core/multiline' # dependency
module Rib; module MultilineHistory
extend Plugin
Shell.use(self)
# --------------- Rib API ---------------
def before_loop
@multiline_trash = 0
super
end
def loop_eval input
return super if MultilineHistory.disabled?
super
ensure
# SyntaxError might mean we're multiline editing
handle_multiline unless multiline?($!)
end
def handle_interrupt
return super if MultilineHistory.disabled?
if multiline_buffer.size > 1
multiline_trash
@multiline_trash += 1
end
super
end
private
def handle_multiline
if multiline_buffer.size > 1
# so multiline editing is considering done here
# TODO: there's no history.pop(size)
(multiline_buffer.size + multiline_trash).times{ history.pop }
history << "\n" + multiline_buffer.join("\n")
end
end
def multiline_trash
@multiline_trash ||= 0
end
end; end
================================================
FILE: lib/rib/more/multiline_history_file.rb
================================================
# frozen_string_literal: true
require 'rib/more/multiline_history'
module Rib; module MultilineHistoryFile
extend Plugin
Shell.use(self)
# --------------- Rib API ---------------
def before_loop
return super if MultilineHistoryFile.disabled?
multiline_history_file_token
super
end
# --------------- Plugin API ---------------
def read_history
return super if MultilineHistoryFile.disabled?
buffer = []
File.exist?(history_file_path) && history.empty? &&
IO.readlines(history_file_path).each{ |line|
if line.end_with?(
"#{config[:multiline_history_file_token]}\n")
buffer << line[0...
-multiline_history_file_token.size-1] + "\n"
else
history << (buffer.join + line).chomp
buffer = []
end
}
end
def write_history
return super if MultilineHistoryFile.disabled?
# TODO: hisotroy.map is MRI 1.9+
config[:history] = history.to_a.map{ |line|
line.gsub("\n", "#{config[:multiline_history_file_token]}\n")
}
super
end
private
def multiline_history_file_token
config[:multiline_history_file_token] ||= ' '
end
end; end
================================================
FILE: lib/rib/more.rb
================================================
# frozen_string_literal: true
# upon session ends
require 'rib/more/multiline_history_file'
# upon formatting output
require 'rib/more/bottomup_backtrace'
require 'rib/more/color'
# upon input
require 'rib/more/multiline_history'
# special tools
require 'rib/more/anchor'
require 'rib/more/caller'
require 'rib/more/edit'
# upon application loads
require 'rib/more/beep'
================================================
FILE: lib/rib/plugin.rb
================================================
# frozen_string_literal: true
module Rib; module Plugin
attr_accessor :disabled
def enable
self.disabled = false
if block_given? then yield else enabled? end
ensure
self.disabled = true if block_given?
end
def disable
self.disabled = true
if block_given? then yield else enabled? end
ensure
self.disabled = false if block_given?
end
def enabled?
!disabled
end
def disabled?
!!disabled
end
# Backward compatibility
def const_missing mod
if Rib.const_defined?(mod)
Rib.warn("Using #{mod} is deprecated, please change to Rib::#{mod}",
"This compatibility layer would be removed in Rib 1.6+",
"Called: #{caller.first}")
Rib.const_get(mod)
else
super
end
end
def self.extended mod
return unless mod.name
snake_name = mod.name.sub(/(\w+::)+?(\w+)$/, '\2').
gsub(/([A-Z][a-z]*)/, '\\1_').downcase[0..-2]
code = (%w[enable disable].map{ |meth|
<<-RUBY
def #{meth}_#{snake_name} &block
#{mod.name}.#{meth}(&block)
end
RUBY
} + %w[enabled? disabled?].map{ |meth|
<<-RUBY
def #{snake_name}_#{meth} &block
#{mod.name}.#{meth}(&block)
end
RUBY
}).join("\n")
Rib.singleton_class.module_eval(code, __FILE__, __LINE__)
end
end; end
================================================
FILE: lib/rib/runner.rb
================================================
# frozen_string_literal: true
require 'rib'
module Rib; module Runner
module_function
def options
@options ||=
[['ruby options:' , '' ],
['-e, --eval LINE' ,
'Evaluate a LINE of code' ],
['-d, --debug' ,
'Set debugging flags (set $DEBUG to true)' ],
['-w, --warn' ,
'Turn warnings on (set $-w and $VERBOSE to true)' ],
['-I, --include PATH' ,
'Specify $LOAD_PATH (may be used more than once)' ],
['-r, --require LIBRARY' ,
'Require the library, before executing your script' ],
['rib options:' , '' ],
['-c, --config FILE', 'Load config from FILE' ],
['-p, --prefix PATH', 'Prefix to locate the app. Default to .'],
['-n, --no-config' , 'Suppress loading any config' ],
['-h, --help' , 'Print this message' ],
['-v, --version' , 'Print the version' ]] +
[['rib commands:' , '']] + commands
end
def commands
@commands ||=
command_paths.map{ |path|
name = File.basename(path)[/^rib\-(.+)$/, 1]
[name, command_descriptions[name] ||
command_descriptions_find(path) || ' '] }
end
def command_paths
@command_paths ||=
Gem.path.map{ |path|
Dir["#{path}/bin/*"].map{ |f|
(File.executable?(f) && File.basename(f) =~ /^rib\-.+$/ && f) ||
nil # a trick to make false to be nil and then
}.compact # this compact could eliminate them
}.flatten
end
def command_descriptions
@command_descriptions ||=
{'all' => 'Load all recommended plugins' ,
'min' => 'Run the minimum essence' ,
'auto' => 'Run as Rails or Rack console (auto-detect)',
'rails' => 'Run as Rails console' ,
'rack' => 'Run as Rack console' }
end
# Extract the text below __END__ in the bin file as the description
def command_descriptions_find path
# FIXME: Can we do better? This is not reliable
File.read(path) =~ /Gem\.activate_bin_path\(['"](.+)['"], ['"](.+)['"],/
(File.read(Gem.bin_path($1, $2))[/\n__END__\n(.+)$/m, 1] || '').strip
end
def run argv=ARGV
(@running_commands ||= []) << Rib.config[:name]
unused = parse(argv)
# we only want to run the loop if we're running the rib command,
# otherwise, it must be a rib app, which we only want to parse
# the arguments and proceed (this is recursive!)
if @running_commands.pop == 'rib'
Rib.warn("Unused arguments: #{unused.inspect}") unless unused.empty?
require 'rib/core' if Rib.config.delete(:mimic_irb)
loop
end
end
def loop retry_times=5
Rib.shell.loop
rescue => e
if retry_times <= 0
Rib.warn("Error: #{e}. Too many retries, give up.")
elsif Rib.shells.last.running?
Rib.warn("Error: #{e}. Relaunching a new shell... ##{retry_times}")
Rib.warn("Backtrace: #{e.backtrace}") if $VERBOSE
Rib.shells.pop
Rib.shells << Rib::Shell.new(Rib.config)
retry_times -= 1
retry
else
Rib.warn("Error: #{e}. Closing.")
Rib.warn("Backtrace: #{e.backtrace}") if $VERBOSE
end
end
def parse argv
unused = []
until argv.empty?
case arg = argv.shift
when /^-e=?(.+)?/, /^--eval=?(.+)?/
Rib.shell.eval_binding.eval(
$1 || argv.shift || '', __FILE__, __LINE__)
when /^-d/, '--debug'
$DEBUG = true
parse_next(argv, arg)
when /^-w/, '--warn'
$-w, $VERBOSE = true, true
parse_next(argv, arg)
when /^-I=?(.+)?/, /^--include=?(.+)?/
paths = ($1 || argv.shift).split(':')
$LOAD_PATH.unshift(*paths)
when /^-r=?(.+)?/, /^--require=?(.+)?/
require($1 || argv.shift)
when /^-c=?(.+)?/, /^--config=?(.+)?/
Rib.config_path = $1 || argv.shift
when /^-p=?(.+)?/, /^--prefix=?(.+)?/
Rib.config[:prefix] = $1 || argv.shift
when /^-n/, '--no-config'
Rib.config_path = Rib::Skip
parse_next(argv, arg)
when /^-h/, '--help'
puts(help)
exit
when /^-v/, '--version'
require 'rib/version'
puts(Rib::VERSION)
exit
when /^[^-]/
load_command(arg)
else
unused << arg
end
end
unused
end
def parse_next argv, arg
argv.unshift("-#{arg[2..-1]}") if arg.size > 2
end
def help
optt = options.transpose
maxn = optt.first.map(&:size).max
maxd = optt.last .map(&:size).max
"Usage: #{Rib.config[:name]}" \
" [ruby OPTIONS] [rib OPTIONS] [rib COMMANDS]\n" +
options.map{ |(name, desc)|
if name.end_with?(':')
name
else
sprintf(" %-*s %-*s", maxn, name, maxd, desc)
end
}.join("\n")
end
def load_command command
bin = "rib-#{command}"
path = which_bin(bin)
if path == ''
Rib.warn(
"Can't find #{bin} in $PATH. Please make sure it is installed,",
"or is there any typo? You can try this to install it:\n" ,
" gem install #{bin}")
else
Rib.config[:name] = bin
load(path)
end
end
def which_bin bin # handle windows here
`which #{bin}`.strip
rescue Errno::ENOENT # probably a windows platform, try where
`where #{bin}`.lines.first.strip
end
end; end
================================================
FILE: lib/rib/shell.rb
================================================
# frozen_string_literal: true
require 'rib/plugin'
require 'rib/api'
module Rib; class Shell
include API
def self.use mod
include mod
end
attr_reader :config
# Create a new shell.
#
# @api public
# @param config [Hash] The config of the shell.
# @option config [String] :config ('~/.rib/config.rb')
# The path to Rib config file.
# @option config [String] :name ('rib')
# The name of the shell. Used for Rib application.
# @option config [String] :result_prompt ('=> ')
# @option config [String] :prompt ('>> ')
# @option config [Binding, Object] :binding (new_private_binding)
# The context of the shell. Could be an Object.
# @option config [Array<String>] :exit ([nil])
# The keywords to exit the shell. `nil` means EOF (ctrl+d).
# @option config [Fixnum] :line (1) The beginning of line number.
# @option config [String] :history_file ('~/.rib/config/history.rb')
# (Only if {Rib::History} plugin is used) The path to history file.
# @option config [Fixnum] :history_size (500)
# (Only if {Rib::History} plugin is used) Maximum numbers of history.
# @option config [Hash<Class, Symbol>] :color (...)
# (Only if {Rib::Color} plugin is used) Data type colors mapping.
# @option config [String] :autoindent_spaces (' ')
# (Only if {Rib::Autoindent} plugin is used) The indented string.
def initialize(config={})
config[:binding] ||= new_private_binding
self.config = {:result_prompt => '=> ',
:prompt => '>> ',
:exit => [nil],
:line => 1 }.merge(config)
stop
end
# Loops shell until user exits
def loop
before_loop
set_trap
start
in_loop
stop
self
rescue Exception => e
Rib.warn("Error while running loop:\n #{format_error(e)}")
raise
ensure
release_trap
after_loop
end
def start
@running = true
end
def stop
@running = false
end
def running?
!!@running
end
def warnings
@warnings ||= []
end
protected
attr_writer :config
def set_trap
@trap_proc = trap('INT'){ raise Interrupt }
end
def release_trap
trap('INT', &@trap_proc) if @trap_proc.kind_of?(Proc)
end
private
# Avoid namespace pollution from rubygems bin stub.
# To be specific, version and str.
def new_private_binding
TOPLEVEL_BINDING.eval <<-RUBY
singleton_class.module_eval do
Rib.warn("Removing existing main...") if method_defined?(:main)
def main; binding; end # any way to define <main> method?
end
ret = main
singleton_class.send(:remove_method, 'main') # never pollute anything
ret
RUBY
end
end; end
================================================
FILE: lib/rib/test/history.rb
================================================
# frozen_string_literal: true
require 'tempfile'
copy :setup_history do
before do
if readline?
::Readline::HISTORY.clear
stub_readline
end
shell(:history_file => history_file)
end
after do
tempfile.unlink if @tempfile
end
def tempfile
@tempfile ||= Tempfile.new('rib')
end
def history_file
tempfile.path
end
end
================================================
FILE: lib/rib/test/multiline.rb
================================================
# frozen_string_literal: true
copy :setup_multiline do
def setup_input str
if readline?
stub_readline(:mock)
else
mock($stdin).gets{ str.chomp }
end
end
def input str
setup_input(str)
mock(shell).throw(:rib_multiline)
end
def input_done str, err=nil
setup_input(str)
if err
mock(shell).print_eval_error(is_a(err)){}
else
mock(shell).print_result(is_a(Object)){}
end
shell.loop_once
ok
end
def check str, err=nil
yield if block_given?
lines = str.split("\n")
lines[0...-1].each{ |line|
input(line)
shell.loop_once
}
input_done(lines.last, err)
end
before do
stub_output
end
end
copy :multiline do
would 'work with no prompt' do
shell.config[:prompt] = ''
check <<~RUBY
def f
0
end
RUBY
end
would 'def f' do
check <<~RUBY
def f
1
end
RUBY
end
would 'class C' do
check <<~RUBY
class C
end
RUBY
end
would 'begin' do
check <<~RUBY
begin
end
RUBY
end
would 'begin with RuntimeError' do
check <<~RUBY, RuntimeError
begin
raise 'multiline raised an error'
end
RUBY
end
would 'do end' do
check <<~RUBY
[].each do
end
RUBY
end
would 'block brace' do
check <<~RUBY
[].each{
}
RUBY
end
would 'hash' do
check <<~RUBY
{
}
RUBY
end
would 'hash value' do
check <<~RUBY
{1 =>
2}
RUBY
end
would 'array' do
check <<~RUBY
[
]
RUBY
end
would 'group' do
check <<~RUBY
(
)
RUBY
end
would 'string double quote' do
check <<~RUBY
"
"
RUBY
end
would 'string single quote' do
check <<~RUBY
'
'
RUBY
end
would 'be hash treated as a block SyntaxError' do
code = <<~RUBY
puts { :x => 10 }.class
RUBY
if RUBY_VERSION >= '3.0.0'
check code do
stub(shell.config[:binding_object]).puts{}
end
else
check code, SyntaxError
end
end
would 'SyntaxError' do
check <<~RUBY, SyntaxError
s-y n
RUBY
end
would 'binary operator +' do
check <<~RUBY
1/1.to_i +
1
RUBY
end
would 'binary operator -' do
check <<~RUBY
1*1.to_i -
1
RUBY
end
would 'binary operator *' do
check <<~RUBY
1-1.to_i *
1
RUBY
end
would 'binary operator /' do
code = <<~RUBY
1+1.to_i /
1
RUBY
if RUBY_VERSION >= '3.0.0'
check code.lines.first, SyntaxError
else
check code
end
end
would 'binary operator |' do
check <<~RUBY
1+1.to_i |
1
RUBY
end
would 'binary operator &' do
check <<~RUBY
1+1.to_i &
1
RUBY
end
would 'binary operator ^' do
check <<~RUBY
1+1.to_i ^
1
RUBY
end
would 'backslash at the end' do
check <<~RUBY
'nice ' \\
'shell'
RUBY
end
end
================================================
FILE: lib/rib/test.rb
================================================
# frozen_string_literal: true
require 'pork/auto'
require 'muack'
Pork::Suite.include(Muack::API)
require 'rib'
copy :rib do
before do
Rib.disable_plugins
end
after do
Muack.verify
end
def shell opts={}
@shell ||= new_shell(opts)
end
def new_shell opts={}
binding_object = Object.new
result = Rib::Shell.new(
{:binding => binding_object.instance_eval{binding},
:binding_object => binding_object}.
merge(opts))
yield(result) if block_given?
result.before_loop
end
def stub_output
stub(shell).print(is_a(String)){}
stub(shell).puts(is_a(String)){}
stub(shell).puts{}
end
def readline?
Rib.constants.map(&:to_s).include?('Readline') &&
Rib::Readline.enabled?
end
def stub_readline meth=:stub
send(meth, ::Readline).readline(is_a(String), true) do
(::Readline::HISTORY << str.chomp).last
end
end
singleton_class.module_eval do
def test_for *plugins, &block
require 'rib/all' # exhaustive tests
rest = Rib.plugins - plugins
before do
Rib.enable_plugins(plugins)
Rib.disable_plugins(rest)
end
describe "enabling #{plugins}" do
block.call
case ENV['TEST_LEVEL']
when '0'
when '1'
test_level1(rest, block)
when '2'
test_level2(rest, block)
when '3'
test_level3(rest, block)
else # test_level3 is too slow because of rr (i guess)
test_level2(rest, block)
end
end
end
def test_level1 rest, block
rest.each{ |target|
target.enable
describe "also enabling #{target}" do
block.call
end
target.disable
}
end
def test_level2 rest, block
rest.combination(2).each{ |targets|
Rib.enable_plugins(targets)
describe "also enabling #{targets.join(', ')}" do
block.call
end
Rib.disable_plugins(targets)
}
end
def test_level3 rest, block
if rest.empty?
block.call
else
rest[0].enable
describe "also enabling #{rest[0]}" do
test_level3(rest[1..-1], block)
end
rest[0].disable
describe "disabling #{rest[0]}" do
test_level3(rest[1..-1], block)
end
end
end
end
end
def main
'rib'
end
Rib::Blackhole = Object.new
b = Rib::Blackhole.singleton_class
b.instance_methods(true).each{ |m|
b.send(:undef_method, m) unless
[:object_id, :__send__, :__id__].include?(m) }
================================================
FILE: lib/rib/version.rb
================================================
# frozen_string_literal: true
module Rib
VERSION = '1.6.3'
end
================================================
FILE: lib/rib.rb
================================================
# frozen_string_literal: true
require 'rib/shell'
require 'rib/version'
module Rib
Skip = Object.new
module_function
# All default Rib configs, would be passed to Shell.new in Rib.shell,
# but calling Shell.new directly won't bring this in.
#
# @api public
def config
@config ||= {:name => 'rib', :prefix => '.', :started_at => Time.now}
end
# All shells in the memory
def shells
@shells ||= []
end
# All shared variables for all shells
def vars
@vars ||= {}
end
# Rib.home is where Rib storing things. By default, it goes to '~/.rib',
# or somewhere containing a 'config.rb' or 'history.rb' in the order of
# './.rib' (project specific config), or '~/.rib' (home config), or
# '~/.config/rib' (home config, residing in ~/.config)
#
# @api public
def home
ENV['RIB_HOME'] ||= File.expand_path(
["#{config[:prefix]}/.rib", '~/.rib', '~/.config/rib'].find{ |path|
File.exist?(File.expand_path(path))
} || '~/.rib'
)
end
# Convenient shell accessor, which would just give you current last shell
# or create one and load the config file. If you need a clean shell which
# does not load config file, use Shell.new instead.
#
# @api public
def shell
shells.last || begin
require_config if config_path && config_path != Skip
(shells << Shell.new(config)).last
end
end
# All plugins which have been loaded into the memory regardless
# it's enabled or not.
#
# @api public
def plugins
Shell.ancestors.drop(1).select{ |a| a.singleton_class < Plugin }
end
# Convenient way to disable all plugins in the memory.
# This could also take a list of plugins and disable them.
#
# @api public
# @param plugs [Array] (Rib.plugins) Plugins which would be disabled.
def disable_plugins plugs=plugins
plugs.each(&:disable)
end
# Convenient way to enable all plugins in the memory.
# This could also take a list of plugins and enable them.
#
# @api public
# @param plugs [Array] (Rib.plugins) Plugins which would be enabled.
def enable_plugins plugs=plugins
plugs.each(&:enable)
end
# Load (actually require) the config file if it exists.
# This might emit warnings if there's some error while loading it.
#
# @api public
def require_config
result = require(config_path) if File.exist?(config_path)
Rib.say("Config loaded from: #{config_path}") if $VERBOSE && result
result
rescue StandardError, LoadError, SyntaxError => e
Rib.warn("Error loading #{config_path}\n" \
" #{Rib::API.format_error(e)}")
end
# The config path where Rib tries to load upon Rib.shell.
# It is depending on where Rib.home was discovered if
# no specific config path was specified via -c or --config command
#
# @api public
def config_path
@config_path ||= File.join(home, 'config.rb')
end
def config_path= new_path
@config_path = new_path
end
# Say (print to $stdout, with colors in the future, maybe)
# something by the name of Rib.
#
# @api public
# @param words [Array[String]] Words you want to say.
def say *words
$stdout.puts(Rib.prepare(words))
end
# Warn (print to $stderr, with colors in the future, maybe)
# something by the name of Rib.
#
# @api public
# @param words [Array[String]] Words you want to warn.
def warn *words
$stderr.puts(Rib.prepare(words))
end
# Warn (print to $stderr, with colors in the future, maybe)
# something by the name of Rib and then exit(1).
#
# @api public
# @param words [Array[String]] Words you want to warn before aborting.
def abort *words
warn(words)
exit(1)
end
def silence
w, v = $-w, $VERBOSE
$-w, $VERBOSE = false, false
yield
ensure
$-w, $VERBOSE = w, v
end
private
def self.prepare words
name = config[:name]
"#{name}: #{words.join("\n#{' '*(name.size+2)}")}"
end
end
================================================
FILE: rib.gemspec
================================================
# -*- encoding: utf-8 -*-
# stub: rib 1.6.3 ruby lib
Gem::Specification.new do |s|
s.name = "rib".freeze
s.version = "1.6.3".freeze
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
s.require_paths = ["lib".freeze]
s.authors = ["Lin Jen-Shin (godfat)".freeze]
s.date = "2026-01-20"
s.description = "Ruby-Interactive-ruBy -- Yet another interactive Ruby shell\n\nRib is based on the design of [ripl][] and the work of [ripl-rc][], some of\nthe features are also inspired by [pry][]. The aim of Rib is to be fully\nfeatured and yet very easy to opt-out or opt-in other features. It shall\nbe simple, lightweight and modular so that everyone could customize Rib.\n\n[ripl]: https://github.com/cldwalker/ripl\n[ripl-rc]: https://github.com/godfat/ripl-rc\n[pry]: https://github.com/pry/pry".freeze
s.email = ["godfat (XD) godfat.org".freeze]
s.executables = [
"rib".freeze,
"rib-all".freeze,
"rib-auto".freeze,
"rib-min".freeze,
"rib-rack".freeze,
"rib-rails".freeze]
s.files = [
".gitignore".freeze,
".gitlab-ci.yml".freeze,
".gitmodules".freeze,
"CHANGES.md".freeze,
"Gemfile".freeze,
"LICENSE".freeze,
"README.md".freeze,
"Rakefile".freeze,
"TODO.md".freeze,
"bin/rib".freeze,
"bin/rib-all".freeze,
"bin/rib-auto".freeze,
"bin/rib-min".freeze,
"bin/rib-rack".freeze,
"bin/rib-rails".freeze,
"lib/rib.rb".freeze,
"lib/rib/all.rb".freeze,
"lib/rib/api.rb".freeze,
"lib/rib/app/auto.rb".freeze,
"lib/rib/app/rack.rb".freeze,
"lib/rib/app/rails.rb".freeze,
"lib/rib/config.rb".freeze,
"lib/rib/core.rb".freeze,
"lib/rib/core/completion.rb".freeze,
"lib/rib/core/history.rb".freeze,
"lib/rib/core/last_value.rb".freeze,
"lib/rib/core/multiline.rb".freeze,
"lib/rib/core/readline.rb".freeze,
"lib/rib/core/squeeze_history.rb".freeze,
"lib/rib/core/strip_backtrace.rb".freeze,
"lib/rib/debug.rb".freeze,
"lib/rib/extra/autoindent.rb".freeze,
"lib/rib/extra/byebug.rb".freeze,
"lib/rib/extra/hirb.rb".freeze,
"lib/rib/extra/paging.rb".freeze,
"lib/rib/extra/spring.rb".freeze,
"lib/rib/more.rb".freeze,
"lib/rib/more/anchor.rb".freeze,
"lib/rib/more/beep.rb".freeze,
"lib/rib/more/bottomup_backtrace.rb".freeze,
"lib/rib/more/caller.rb".freeze,
"lib/rib/more/color.rb".freeze,
"lib/rib/more/edit.rb".freeze,
"lib/rib/more/multiline_history.rb".freeze,
"lib/rib/more/multiline_history_file.rb".freeze,
"lib/rib/plugin.rb".freeze,
"lib/rib/runner.rb".freeze,
"lib/rib/shell.rb".freeze,
"lib/rib/test.rb".freeze,
"lib/rib/test/history.rb".freeze,
"lib/rib/test/multiline.rb".freeze,
"lib/rib/version.rb".freeze,
"rib.gemspec".freeze,
"task/README.md".freeze,
"task/gemgem.rb".freeze,
"test/core/test_completion.rb".freeze,
"test/core/test_history.rb".freeze,
"test/core/test_last_value.rb".freeze,
"test/core/test_multiline.rb".freeze,
"test/core/test_readline.rb".freeze,
"test/core/test_squeeze_history.rb".freeze,
"test/core/test_strip_backtrace.rb".freeze,
"test/extra/test_autoindent.rb".freeze,
"test/more/test_anchor.rb".freeze,
"test/more/test_beep.rb".freeze,
"test/more/test_caller.rb".freeze,
"test/more/test_color.rb".freeze,
"test/more/test_multiline_history.rb".freeze,
"test/test_api.rb".freeze,
"test/test_plugin.rb".freeze,
"test/test_runner.rb".freeze,
"test/test_shell.rb".freeze]
s.homepage = "https://github.com/godfat/rib".freeze
s.licenses = ["Apache-2.0".freeze]
s.rubygems_version = "4.0.4".freeze
s.summary = "Ruby-Interactive-ruBy -- Yet another interactive Ruby shell".freeze
s.test_files = [
"test/core/test_completion.rb".freeze,
"test/core/test_history.rb".freeze,
"test/core/test_last_value.rb".freeze,
"test/core/test_multiline.rb".freeze,
"test/core/test_readline.rb".freeze,
"test/core/test_squeeze_history.rb".freeze,
"test/core/test_strip_backtrace.rb".freeze,
"test/extra/test_autoindent.rb".freeze,
"test/more/test_anchor.rb".freeze,
"test/more/test_beep.rb".freeze,
"test/more/test_caller.rb".freeze,
"test/more/test_color.rb".freeze,
"test/more/test_multiline_history.rb".freeze,
"test/test_api.rb".freeze,
"test/test_plugin.rb".freeze,
"test/test_runner.rb".freeze,
"test/test_shell.rb".freeze]
end
================================================
FILE: test/core/test_completion.rb
================================================
require 'rib/test'
require 'rib/core/completion'
describe Rib::Completion do
paste :rib
before do
Rib::Completion.enable
end
would 'start bond' do
new_shell do |sh|
eval_binding = sh.method(:eval_binding).source_location
mock(Bond).start(having(eval_binding: is_a(Proc))).peek_args do |*args|
expect(args.first[:eval_binding].source_location).eq eval_binding
args
end
end
expect(Bond).started?
end
end
================================================
FILE: test/core/test_history.rb
================================================
require 'rib/test'
require 'rib/test/history'
require 'rib/core/history'
describe Rib::History do
paste :rib
paste :setup_history
test_for Rib::History do
would '#after_loop save history' do
inputs = %w[blih blah]
shell.history.push(*inputs)
shell.after_loop
expect(File.read(history_file)).eq "#{inputs.join("\n")}\n"
end
would '#before_loop load previous history' do
File.write(history_file, "check\nthe\nmike")
shell.before_loop
expect(shell.history.to_a).eq %w[check the mike]
end
would '#before_loop have empty history if no history file exists' do
expect(shell.history.to_a).eq []
end
would '#read_history be accessible to plugins in #before_loop' do
mod = Module.new do
def read_history
config[:history] = ['pong_read_history']
end
end
klass = Rib::Shell.dup
klass.use(mod)
shell = klass.new.before_loop
expect(shell.history).eq ['pong_read_history']
end
would '#write_history be accessible to plugins in #after_loop' do
mod = Module.new do
def write_history
config[:history] = ['pong_write_history']
end
end
klass = Rib::Shell.dup
klass.use(mod)
shell = klass.new.before_loop.after_loop
expect(shell.history).eq ['pong_write_history']
end
end
end
================================================
FILE: test/core/test_last_value.rb
================================================
require 'rib/test'
require 'rib/core/last_value'
describe Rib::LastValue do
paste :rib
before do
stub_output
stub(Rib).shell{shell}
end
test_for Rib::LastValue do
would 'set last_value' do
mock(shell).get_input{'Rib.last_value'}
mock(shell).get_input{'10**2'}
mock(shell).get_input{'Rib.last_value'}
expect(shell.loop_once).eq [nil, nil]
shell.loop_once
expect(shell.loop_once).eq [100, nil]
end
would 'set last_exception' do
mock(shell).get_input{'XD'}
mock(shell).get_input{'Rib.last_exception'}
shell.loop_once
expect(shell.loop_once.first).kind_of?(NameError)
end
end
end
================================================
FILE: test/core/test_multiline.rb
================================================
require 'rib/test'
require 'rib/test/multiline'
require 'rib/core/multiline'
describe Rib::Multiline do
paste :rib
paste :setup_multiline
test_for Rib::Multiline do
paste :multiline
end
end
================================================
FILE: test/core/test_readline.rb
================================================
require 'rib/test'
require 'rib/core/readline'
describe Rib::Readline do
paste :rib
test_for Rib::Readline do
would '#before_loop set @history' do
expect(shell.history).eq Readline::HISTORY
end
would '#get_input calling Readline.readline' do
mock(Readline).readline(shell.prompt, true){'ok'}
expect(shell.get_input).eq 'ok'
end
end
end
================================================
FILE: test/core/test_squeeze_history.rb
================================================
require 'rib/test'
require 'rib/test/history'
require 'rib/core/squeeze_history'
describe Rib::SqueezeHistory do
paste :rib
paste :setup_history
test_for Rib::History, Rib::SqueezeHistory do
before do
@input = %w[foo bar bar foo bar]
end
would 'after_loop saves squeezed history' do
shell.history.push(*@input)
shell.after_loop
expect(File.read(history_file)).eq %w[foo bar foo bar].join("\n") + "\n"
end
would 'loop_once squeeze history' do
stub_output
stub(shell).get_input{ (shell.history << "'#{@input.shift}'").last }
@input.size.times{ shell.loop_once }
expect(shell.history.to_a).eq %w[foo bar foo bar].map{ |i| "'#{i}'" }
end
would 'be disabled if disabled' do
Rib::SqueezeHistory.disable do
stub_output
stub(shell).get_input{ (shell.history << "'#{@input.shift}'").last }
input = @input.dup
@input.size.times{ shell.loop_once }
expect(shell.history.to_a).eq input.map{ |i| "'#{i}'" }
end
end
end
end
================================================
FILE: test/core/test_strip_backtrace.rb
================================================
require 'rib/test'
require 'rib/core/strip_backtrace'
describe Rib::StripBacktrace do
would 'strip home' do
backtrace = ["#{ENV['HOME']}/test", "/prefix/#{ENV['HOME']}/test"]
expect(Rib::StripBacktrace.strip_home_backtrace(backtrace)).
eq ['~/test', "/prefix/#{ENV['HOME']}/test"]
end
would 'strip current working directory' do
backtrace = [File.expand_path(__FILE__)]
expect(Rib::StripBacktrace.strip_cwd_backtrace(backtrace)).
eq ['test/core/test_strip_backtrace.rb']
end
end
================================================
FILE: test/extra/test_autoindent.rb
================================================
require 'rib/test'
require 'rib/extra/autoindent'
describe Rib::Autoindent do
paste :rib
autoindent = Class.new do
include Rib::Autoindent, Rib::Multiline, Rib::API
def config
{:line => 0, :binding => TOPLEVEL_BINDING, :prompt => '>> '}
end
def stack_size
autoindent_stack.size
end
end
before do
Rib::Multiline.enable
Rib::Autoindent.enable
@indent = autoindent.new
mock(@indent).puts(matching(/^\e/)).times(0)
expect(@indent.stack_size).eq 0
end
def ri input, size
@indent.eval_input(input)
expect(@indent.stack_size).eq size
end
def le input, size
mock(@indent).puts(matching(/^\e/)){}
@indent.eval_input(input)
expect(@indent.stack_size).eq size
end
would 'begin rescue else ensure end' do
ri('begin' , 1)
ri( '1' , 1)
le('rescue' , 1)
ri( '1' , 1)
le('rescue=>e' , 1)
le('rescue => e' , 1)
le('rescue =>e' , 1)
le('rescue E=>e ' , 1)
le('rescue E' , 1)
le('rescue E => e ', 1)
le('rescue E=> e' , 1)
le('rescue E =>e ' , 1)
le('else' , 1)
ri( '1' , 1)
le('ensure' , 1)
ri( '1' , 1)
le('end while nil' , 0)
end
would 'def rescue else ensure end' do
ri('def f a' , 1)
ri( 'if a' , 2)
le( 'end' , 1)
le('rescue' , 1)
ri( '1' , 1)
le('rescue=>e' , 1)
le('rescue => e' , 1)
le('rescue =>e' , 1)
le('rescue E=>e ' , 1)
le('rescue E' , 1)
le('rescue E => e ', 1)
le('rescue E=> e' , 1)
le('rescue E =>e ' , 1)
le('else' , 1)
ri( '1' , 1)
le('ensure' , 1)
ri( '1' , 1)
le('end while nil' , 0)
end
would 'if elsif else end' do
ri('if true' , 1)
ri( 'if false' , 2)
ri( '1' , 2)
le( 'end' , 1)
ri( 'if true' , 2)
le( 'elsif true' , 2)
ri( '1' , 2)
le( 'else' , 2)
ri( '1' , 2)
le( 'end' , 1)
ri( 'if 1' , 2)
ri( 'if 2' , 3)
le( 'end' , 2)
le( 'end' , 1)
le('end' , 0)
end
would 'unless else end' do
ri('unless 1' , 1)
ri( 'unless 1' , 2)
ri( '1' , 2)
le( 'end ' , 1)
le('else' , 1)
ri( '1' , 1)
le('end' , 0)
end
would 'case when else end' do
ri('case 1' , 1)
le('when 1' , 1)
ri( '1' , 1)
le('when 2' , 1)
ri(' if 1' , 2)
le(' end' , 1)
le('else' , 1)
ri( '1' , 1)
le('end' , 0)
end
would 'class Object end' do
ri('class Object' , 1)
ri( 'if true' , 2)
le( 'end' , 1)
le('end' , 0)
end
would 'module Rib end' do
ri('module Rib' , 1)
ri( 'module_function', 1)
ri( 'if true' , 2)
le( 'end' , 1)
le('end' , 0)
end
would 'while end' do
ri('while false' , 1)
ri( 'if true' , 2)
le( 'end' , 1)
le('end' , 0)
end
would 'for end' do
ri('for x in 1..2' , 1)
ri( 'if true' , 2)
le( 'end' , 1)
le('end' , 0)
end
would 'until end' do
ri('until true' , 1)
ri( 'if true' , 2)
le( 'end' , 1)
le('end' , 0)
end
would 'do end' do
ri("to_s''do" , 1)
ri( "to_s '' do" , 2)
le( 'end' , 1)
ri( 'to_s "" do' , 2)
le( 'end' , 1)
ri( 'to_s // do' , 2)
le( 'end' , 1)
le('end' , 0)
end
would '{}' do
ri('{' , 1)
ri( ':a => :b' , 1)
le('}' , 0)
end
would '[].each{}' do
ri('[].each{' , 1)
ri( '0' , 1)
ri( '[].each {' , 2)
le( '}' , 1)
le('}' , 0)
end
would '()' do
ri('(' , 1)
ri( '0' , 1)
le(')' , 0)
end
would '{}.dig()' do
ri('{}.dig(' , 1)
ri( '0,' , 1)
ri( '1' , 1)
le(')' , 0)
end
would '[]' do
ri('[' , 1)
ri( '0,' , 1)
ri( '1,' , 1)
ri( '[' , 2)
ri( '2' , 2)
le( ']' , 1)
le(']' , 0)
end
end
================================================
FILE: test/more/test_anchor.rb
================================================
require 'rib/test'
require 'rib/more/anchor'
require 'rib/core/multiline'
require 'rib/test/multiline'
describe Rib::Anchor do
paste :rib
paste :setup_multiline
before do
Rib::Anchor.enable
end
describe '#anchor?' do
would 'give true when anchoring' do
stub(Rib).shell{shell}
mock(shell).get_input do
expect(shell).anchor?
mock(shell).puts{}
nil
end
Rib.anchor 'test'
end
would 'give false when not anchoring' do
expect(new_shell).not.anchor?
end
end
describe '.stop_anchors' do
def anchor_deeper shell, index
mock(shell).get_input do
mock(shell).puts.times(0)
expect(shell).anchor?
expect(shell.loop_eval('self')).eq index
mock_deeper(index + 1)
'Rib.anchor self + 1'
end
end
def escape shell
mock(shell).get_input do
'Rib.stop_anchors'
end
end
def mock_deeper index
mock(Rib).shell.times(2) # ignore first 2 calls, see Rib.anchor
mock(Rib).shell.peek_return do |deeper_shell|
if index < 5
anchor_deeper(deeper_shell, index)
else
escape(deeper_shell)
end
deeper_shell
end
end
would 'exit all anchors' do
shell = Rib.shell
mock(shell).get_input do
mock_deeper(0)
'Rib.anchor 0'
end
mock(shell).get_input{}
mock(shell).puts{}
shell.loop
end
end
test_for Rib::Anchor, Rib::Multiline do
paste :multiline
end
end
================================================
FILE: test/more/test_beep.rb
================================================
require 'rib/test'
require 'rib/more/beep'
describe Rib::Beep do
paste :rib
before do
Rib::Beep.enable
end
def verify delay, threshold=nil, &block
shell(:started_at => Time.now - delay,
:beep_threshold => threshold, &block)
stub_output
mock(shell).get_input{}
shell.loop
ok
end
def expect_beep sh
mock(sh).print("\a"){}
end
def unexpect_beep sh
stub(sh).print.with_any_args{ flunk }
end
describe 'beep' do
would 'beep if loading too long' do
verify(10, &method(:expect_beep))
end
would 'be configurable via beep_threshold' do
verify(2, 1, &method(:expect_beep))
end
end
describe 'not beep' do
would 'not beep if not loading long' do
verify(2, &method(:unexpect_beep))
end
would 'be configurable via beep_threshold' do
verify(10, 15, &method(:unexpect_beep))
end
end
end
================================================
FILE: test/more/test_caller.rb
================================================
require 'rib/test'
require 'rib/more/caller'
describe Rib::Caller do
paste :rib
test_for Rib::Caller do
would 'puts some backtrace' do
mock(Rib.shell).puts(is_a(String)){ ok }
Rib.caller
end
end
end
================================================
FILE: test/more/test_color.rb
================================================
require 'rib/test'
require 'rib/more/color'
describe Rib::Color do
paste :rib
before do
Rib::Color.enable
end
color = Class.new do
include Rib::Color
def colors
@colors ||= Rib::Shell.new.before_loop.config[:color]
end
def inspect_result result
result.inspect
end
end.new
would 'give correct color' do
color.send(:format_color,
[{0 => :a}, 'b', [nil, {false => Object}], {true => Exception.new}]).
should.eq \
"\e[34m[\e[0m\e[34m{\e[0m\e[31m0\e[0m\e[34m=>\e[0m\e[36m:a\e[0m\e" \
"[34m}\e[0m\e[34m, \e[0m\e[32m\"b\"\e[0m\e[34m, \e[0m\e[34m[\e[0m" \
"\e[35mnil\e[0m\e[34m, \e[0m\e[34m{\e[0m\e[35mfalse\e[0m\e[34m=>" \
"\e[0m\e[33mObject\e[0m\e[34m}\e[0m\e[34m]\e[0m\e[34m, \e[0m\e[34m"\
"{\e[0m\e[35mtrue\e[0m\e[34m=>\e[0m\e[35m#<Exception: Exception>" \
"\e[0m\e[34m}\e[0m\e[34m]\e[0m"
end
would 'inspect recursive array and hash just like built-in inspect' do
a = []
a << a
h = {}
h[0] = h
color.send(:format_color, [a, h]).should.eq \
"\e[34m[\e[0m\e[34m[\e[0m\e[34m[...]\e[0m\e[34m]\e[0m\e[34m, \e[0m" \
"\e[34m{\e[0m\e[31m0\e[0m\e[34m=>\e[0m\e[34m{...}\e[0m\e[34m}\e[0m" \
"\e[34m]\e[0m"
end
# regression test
would "colorize errors with `/' inside" do
error = Class.new(Exception)
begin
line = __LINE__; raise error
rescue error => e
msg = "test/more/#{Rib::Color.yellow{'test_color.rb'}}:" \
"#{Rib::Color.red{line}}:in #{Rib::Color.green}"
Rib::Color.colorize_backtrace(e.backtrace).first.should =~ \
Regexp.new(
"#{Regexp.escape(msg)}(?:`|').+'#{Regexp.escape(Rib::Color.reset)}")
end
end
would 'colorize warnings' do
shell = new_shell
shell.warn('test')
expect(shell.warnings).eq ["\e[31mtest\e[0m"]
end
end
================================================
FILE: test/more/test_multiline_history.rb
================================================
require 'rib/test'
require 'rib/test/multiline'
require 'rib/more/multiline_history'
describe Rib::MultilineHistory do
paste :rib
paste :setup_multiline
def check str, err=nil
shell.history.clear
yield if block_given?
with_history(str, err)
@shell = nil
stub_output
shell.history.clear
shell.history << 'old history'
yield if block_given?
with_history(str, err, 'old history')
end
def with_history str, err, *prefix
lines = str.split("\n")
lines[0...-1].inject([]){ |result, line|
input(line)
shell.loop_once
result << line
expect(shell.history.to_a).eq prefix + result
result
}
input_done(lines.last, err)
history = if lines.size == 1
lines.first
else
"\n#{lines.join("\n")}"
end
expect(shell.history.to_a).eq prefix + [history]
end
test_for Rib::History, Rib::Multiline, Rib::MultilineHistory do
paste :multiline
end
end
================================================
FILE: test/test_api.rb
================================================
require 'rib/test'
require 'rib/shell'
describe Rib::API do
paste :rib
Rib::API.instance_methods.delete_if{ |e| e[/=$/] }.each do |meth|
would "##{meth} be accessible to plugins" do
mod = Module.new do
define_method meth do
"pong_#{meth}"
end
end
klass = Rib::Shell.dup
klass.use(mod)
expect(klass.new.send(meth)).eq "pong_#{meth}"
end
end
would 'emit a warning whenever result is not a string' do
object = Class.new{ alias_method :inspect, :object_id }.new
mock(shell).get_input{'object'}
mock(shell).loop_eval('object'){object}
mock(shell).puts("=> #{object.object_id}"){}
mock($stderr).puts(including("#{object.class}#inspect")){}
shell.loop_once
ok
end
describe '#warn' do
would 'append a warning message to warnings' do
shell.warn('test')
expect(shell.warnings).eq ['test']
end
end
describe '#flush_warnings' do
before do
shell.warn('test')
mock($stderr).puts('rib: test'){}
end
would 'warn to $stderr from #warnings' do
shell.send(:flush_warnings)
ok
end
end
end
================================================
FILE: test/test_plugin.rb
================================================
require 'rib/test'
require 'rib/all'
describe Rib::Plugin do
paste :rib
before do
@names = Dir[File.expand_path(
"#{File.dirname(__FILE__)}/../lib/rib/{core,more,zore}/*.rb")].
map {|path| File.basename(path)[0..-4] }
@mods = Rib.plugins
end
would 'have shortcut methods' do
@names.each do |name|
%w[enable disable].each do |meth|
expect(Rib).respond_to?("#{meth}_#{name}")
end
%w[enabled? disabled?].each do |meth|
expect(Rib).respond_to?("#{name}_#{meth}")
end
end
end
would 'be the same as mod methods' do
@mods.shuffle.take(@mods.size/2).each(&:disable)
@names.each do |name|
%w[enabled? disabled?].each do |meth|
expect(Rib.send("#{name}_#{meth}")).eq \
@mods.find{ |mod|
mod.name[/::\w+$/].tr(':', '') ==
name.gsub(/([^_]+)/){$1.capitalize}.tr('_', '') }.
send(meth)
end
end
end
would 'have backward compatibility for accessing Shell' do
mock(Rib).warn(
is_a(String), is_a(String), including("#{__FILE__}:47")){ok}
Module.new.module_eval <<-RUBY, __FILE__, __LINE__ + 1
extend Rib::Plugin
Shell
RUBY
end
end
================================================
FILE: test/test_runner.rb
================================================
require 'rib/test'
require 'rib/runner'
describe Rib::Runner do
paste :rib
before do
mock(Rib).shell{ shell }.times(2)
end
def input *args
args.each{ |item| mock(shell).get_input{ item } }
mock(shell).get_input{}
end
def output *args
args.each{ |item| mock(shell).puts("=> #{item}"){} }
mock(shell).puts{}
end
would '-e' do
input('a')
output('1')
expect(Rib::Runner.run(%w[-ea=1])).eq shell
end
would '-e nothing' do
input
output
expect(Rib::Runner.run(%w[-e])).eq shell
end
def verify_app_e argv
input('a')
output('1')
conf = {:name => 'rib'}
min = 'rib-min'
mock(Rib::Runner).which_bin(min){ min }
mock(Rib::Runner).load(min){ Rib::Runner.run(argv) }
stub(Rib).config{ conf }
expect(Rib::Runner.run(argv)).eq shell
end
would 'min -e' do
verify_app_e(%w[min -ea=1])
end
would '-e min' do
verify_app_e(%w[-ea=1 min])
end
end
================================================
FILE: test/test_shell.rb
================================================
require 'rib/test'
require 'rib/shell'
describe Rib::Shell do
paste :rib
describe '#loop' do
def input str=Rib::Skip
mock(shell).get_input{if block_given? then yield else str end}
shell.loop
ok
end
would 'exit' do input('exit' ) end
would 'also exit' do input(' exit') end
would 'ctrl+d' do mock(shell).puts{} ; input(nil) end
would ':q' do shell.config[:exit] << ':q'; input(':q') end
would '\q' do shell.config[:exit] << '\q'; input('\q') end
would 'not puts anything if it is not running' do
mock(shell).puts.times(0)
shell.eval_binding.eval('self').instance_variable_set(:@shell, shell)
input('@shell.stop; throw :rib_exit')
end
describe 'trap' do
before do
@token = Class.new(Exception)
@old_trap = trap('INT'){ raise @token }
mock(shell).handle_interrupt{ mock(shell).get_input{'exit'} }
end
after do
trap('INT', &@old_trap)
end
def interrupt
Process.kill('SIGINT', Process.pid)
sleep
end
would 'fence and restore ctrl+c interruption' do
input{ interrupt }
expect.raise(@token){ interrupt }
end
end
end
describe '#loop_once' do
def input str=nil
if block_given?
mock(shell).get_input{ yield }
else
mock(shell).get_input{ str }
end
shell.loop_once
ok
end
would 'handles ctrl+c' do
mock(shell).handle_interrupt{}
input{ raise Interrupt }
end
would 'prints result' do
mock(shell).puts('=> "mm"'){}
input('"m" * 2')
end
%w[next break].each do |keyword|
would "handle #{keyword}" do
mock(shell).puts(matching(/^SyntaxError:/)){}
input(keyword)
end
end
would 'error in print_result' do
mock(Rib).warn(matching(/Error while printing result.*BOOM/m)){}
input('obj = Object.new; def obj.inspect; raise "BOOM"; end; obj')
end
would 'not crash if user input is a blackhole' do
mock(Rib).warn(matching(/Error while printing result/)){}
input('Rib::Blackhole')
end
would 'print error from eval' do
mock(shell).puts(matching(/RuntimeError/)){}
input('raise "blah"')
end
end
describe '#prompt' do
would 'be changeable' do
shell.config[:prompt] = '> '
expect(shell.prompt).eq '> '
end
end
describe '#eval_input' do
before do
@line = shell.config[:line]
end
would 'line' do
shell.eval_input('10 ** 2')
expect(shell.config[:line]).eq @line + 1
end
would 'print error and increments line' do
result, err = shell.eval_input('{')
expect(result).eq nil
expect(err).kind_of?(SyntaxError)
expect(shell.config[:line]).eq @line + 1
end
end
describe '#running?' do
would 'have complete flow' do
expect(shell).not.running?
mock(shell).get_input do
expect(shell).running?
mock(shell).puts{}
nil
end
shell.loop
expect(shell).not.running?
end
end
describe '#stop' do
would 'stop the loop if it is stopped' do
mock(shell).get_input do
expect(shell).running?
shell.stop
expect(shell).not.running?
'Rib::Skip'
end
shell.loop
end
end
would 'call after_loop even if in_loop raises' do
mock(shell).loop_once{ raise 'boom' }
mock(Rib).warn(is_a(String)){}
mock(shell).after_loop{}
expect.raise(RuntimeError) do
shell.loop
end
end
would 'have empty binding' do
expect(shell(:binding => nil).eval_input('local_variables').first).empty?
end
would 'not pollute main' do
expect(shell(:binding => nil).eval_input('main').first).eq 'rib'
end
would 'be main' do
expect(shell(:binding => nil).eval_input('self.inspect').first).eq 'main'
end
would 'warn on removing main' do
mock(TOPLEVEL_BINDING.eval('singleton_class')).method_defined?(:main) do
true
end
mock(Rib).warn(is_a(String)){}
expect(shell(:binding => nil).eval_input('main').first).eq 'rib'
end
end
gitextract_3eo0hgho/
├── .gitignore
├── .gitlab-ci.yml
├── .gitmodules
├── CHANGES.md
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── TODO.md
├── asciicast.json
├── bin/
│ ├── rib
│ ├── rib-all
│ ├── rib-auto
│ ├── rib-min
│ ├── rib-rack
│ └── rib-rails
├── lib/
│ ├── rib/
│ │ ├── all.rb
│ │ ├── api.rb
│ │ ├── app/
│ │ │ ├── auto.rb
│ │ │ ├── rack.rb
│ │ │ └── rails.rb
│ │ ├── config.rb
│ │ ├── core/
│ │ │ ├── completion.rb
│ │ │ ├── history.rb
│ │ │ ├── last_value.rb
│ │ │ ├── multiline.rb
│ │ │ ├── readline.rb
│ │ │ ├── squeeze_history.rb
│ │ │ └── strip_backtrace.rb
│ │ ├── core.rb
│ │ ├── debug.rb
│ │ ├── extra/
│ │ │ ├── autoindent.rb
│ │ │ ├── byebug.rb
│ │ │ ├── hirb.rb
│ │ │ ├── paging.rb
│ │ │ └── spring.rb
│ │ ├── more/
│ │ │ ├── anchor.rb
│ │ │ ├── beep.rb
│ │ │ ├── bottomup_backtrace.rb
│ │ │ ├── caller.rb
│ │ │ ├── color.rb
│ │ │ ├── edit.rb
│ │ │ ├── multiline_history.rb
│ │ │ └── multiline_history_file.rb
│ │ ├── more.rb
│ │ ├── plugin.rb
│ │ ├── runner.rb
│ │ ├── shell.rb
│ │ ├── test/
│ │ │ ├── history.rb
│ │ │ └── multiline.rb
│ │ ├── test.rb
│ │ └── version.rb
│ └── rib.rb
├── rib.gemspec
└── test/
├── core/
│ ├── test_completion.rb
│ ├── test_history.rb
│ ├── test_last_value.rb
│ ├── test_multiline.rb
│ ├── test_readline.rb
│ ├── test_squeeze_history.rb
│ └── test_strip_backtrace.rb
├── extra/
│ └── test_autoindent.rb
├── more/
│ ├── test_anchor.rb
│ ├── test_beep.rb
│ ├── test_caller.rb
│ ├── test_color.rb
│ └── test_multiline_history.rb
├── test_api.rb
├── test_plugin.rb
├── test_runner.rb
└── test_shell.rb
SYMBOL INDEX (291 symbols across 40 files)
FILE: lib/rib.rb
type Rib (line 6) | module Rib
function config (line 14) | def config
function shells (line 19) | def shells
function vars (line 24) | def vars
function home (line 34) | def home
function shell (line 47) | def shell
function plugins (line 58) | def plugins
function disable_plugins (line 67) | def disable_plugins plugs=plugins
function enable_plugins (line 76) | def enable_plugins plugs=plugins
function require_config (line 84) | def require_config
function config_path (line 98) | def config_path
function config_path= (line 102) | def config_path= new_path
function say (line 111) | def say *words
function warn (line 120) | def warn *words
function abort (line 129) | def abort *words
function silence (line 134) | def silence
function prepare (line 143) | def self.prepare words
FILE: lib/rib/api.rb
type Rib (line 3) | module Rib; module API
type API (line 3) | module API
function before_loop (line 5) | def before_loop
function after_loop (line 10) | def after_loop
function handle_interrupt (line 15) | def handle_interrupt; puts ; end
function prompt (line 17) | def prompt ; config[:prompt] ; end
function result_prompt (line 19) | def result_prompt; config[:result_prompt] ; end
function name (line 21) | def name ; config[:name] ; end
function eval_binding (line 23) | def eval_binding ; config[:binding] ; end
function line (line 25) | def line ; config[:line] ; end
function started_at (line 27) | def started_at ; config[:started_at] ; end
function in_loop (line 30) | def in_loop
function loop_once (line 36) | def loop_once
function get_input (line 58) | def get_input
function eval_input (line 68) | def eval_input input
function loop_eval (line 79) | def loop_eval input
function puts (line 87) | def puts str=''
function print_result (line 92) | def print_result result
function print_eval_error (line 99) | def print_eval_error err
function warn (line 105) | def warn message
function format_result (line 110) | def format_result result
function inspect_result (line 114) | def inspect_result result
function format_error (line 122) | def format_error err
function get_error (line 129) | def get_error err
function format_backtrace (line 134) | def format_backtrace backtrace
function equal_rib_skip (line 139) | def equal_rib_skip result
function flush_warnings (line 145) | def flush_warnings
FILE: lib/rib/app/auto.rb
type Rib (line 3) | module Rib; module Auto
type Auto (line 3) | module Auto
function load (line 5) | def load
FILE: lib/rib/app/rack.rb
type Rib (line 3) | module Rib; module Rack
type Rack (line 3) | module Rack
function load (line 7) | def load
function load_rack (line 13) | def load_rack
function rack? (line 22) | def rack?
function configru_path (line 26) | def configru_path
FILE: lib/rib/app/rails.rb
type Rib (line 3) | module Rib; module Rails
type Rails (line 3) | module Rails
function load (line 5) | def load
function load_rails (line 11) | def load_rails
function load_rails2 (line 21) | def load_rails2
function load_rails3 (line 40) | def load_rails3
function optparse_env (line 51) | def optparse_env
function optparse_rails (line 59) | def optparse_rails
function rails? (line 108) | def rails?
function path_for (line 113) | def path_for file
FILE: lib/rib/core/completion.rb
type Rib (line 5) | module Rib; module Completion
type Completion (line 5) | module Completion
function before_loop (line 11) | def before_loop
FILE: lib/rib/core/history.rb
type Rib (line 6) | module Rib; module History
type History (line 6) | module History
function before_loop (line 12) | def before_loop
function after_loop (line 22) | def after_loop
function get_input (line 29) | def get_input
function history (line 37) | def history; config[:history] ||= []; end
function read_history (line 40) | def read_history
function write_history (line 47) | def write_history
function history_file (line 56) | def history_file
function history_file_path (line 60) | def history_file_path
function history_size (line 64) | def history_size
FILE: lib/rib/core/last_value.rb
type Rib (line 5) | module Rib; module LastValue
type LastValue (line 5) | module LastValue
function print_result (line 11) | def print_result result
function print_eval_error (line 17) | def print_eval_error err
type Imp (line 25) | module Imp
function last_value (line 26) | def last_value
function last_exception (line 30) | def last_exception
FILE: lib/rib/core/multiline.rb
type Rib (line 6) | module Rib; module Multiline
type Multiline (line 6) | module Multiline
function loop_once (line 79) | def loop_once
function loop_eval (line 89) | def loop_eval input
function print_eval_error (line 99) | def print_eval_error err
function prompt (line 108) | def prompt
function handle_interrupt (line 118) | def handle_interrupt
function multiline? (line 131) | def multiline? err
function multiline_prompt (line 135) | def multiline_prompt
function multiline_buffer (line 141) | def multiline_buffer
FILE: lib/rib/core/readline.rb
type Rib (line 6) | module Rib; module Readline
type Readline (line 6) | module Readline
function before_loop (line 12) | def before_loop
function get_input (line 18) | def get_input
function last (line 25) | def (::Readline::HISTORY).last
FILE: lib/rib/core/squeeze_history.rb
type Rib (line 5) | module Rib; module SqueezeHistory
type SqueezeHistory (line 5) | module SqueezeHistory
function loop_once (line 12) | def loop_once
function write_history (line 28) | def write_history
function squeezed_history (line 37) | def squeezed_history
FILE: lib/rib/core/strip_backtrace.rb
type Rib (line 5) | module Rib; module StripBacktrace
type StripBacktrace (line 5) | module StripBacktrace
function format_error (line 11) | def format_error err
function get_error (line 17) | def get_error err
function format_backtrace (line 23) | def format_backtrace backtrace
function strip_home_backtrace (line 30) | def strip_home_backtrace backtrace
function strip_cwd_backtrace (line 34) | def strip_cwd_backtrace backtrace
function strip_rib_backtrace (line 38) | def strip_rib_backtrace backtrace
function replace_path_prefix (line 43) | def replace_path_prefix prefix, substitute, path
FILE: lib/rib/extra/autoindent.rb
type Rib (line 7) | module Rib; module Autoindent
type Autoindent (line 7) | module Autoindent
function before_loop (line 71) | def before_loop
function get_input (line 77) | def get_input
function eval_input (line 94) | def eval_input raw_input
function detect_autoindent (line 105) | def detect_autoindent input
function handle_autoindent (line 120) | def handle_autoindent input, indent, err
function handle_last_line (line 142) | def handle_last_line input,
function current_autoindent (line 152) | def current_autoindent size=autoindent_stack.size
function autoindent_spaces (line 156) | def autoindent_spaces
function autoindent_stack (line 160) | def autoindent_stack
FILE: lib/rib/extra/byebug.rb
type Rib (line 8) | module Rib; module Byebug
type Byebug (line 8) | module Byebug
function before_loop (line 12) | def before_loop
type Imp (line 19) | module Imp
function byebug (line 20) | def byebug
function location (line 26) | def location
function step (line 30) | def step times=1
function next (line 34) | def next lines=1
function finish (line 38) | def finish
type Byebug (line 46) | module Byebug
class RibProcessor (line 47) | class RibProcessor < CommandProcessor
method start (line 48) | def self.start
method at_line (line 56) | def at_line
method at_return (line 60) | def at_return(_return_value)
method at_end (line 64) | def at_end
method at_breakpoint (line 68) | def at_breakpoint(breakpoint)
method location (line 72) | def location
method print_location (line 78) | def print_location
method resume_rib (line 83) | def resume_rib
method perform (line 99) | def perform action, args
FILE: lib/rib/extra/hirb.rb
type Rib (line 5) | module Rib; module Hirb
type Hirb (line 5) | module Hirb
function format_result (line 11) | def format_result result
FILE: lib/rib/extra/paging.rb
type Rib (line 5) | module Rib; module Paging
type Paging (line 5) | module Paging
function puts (line 12) | def puts str=''
function one_screen? (line 23) | def one_screen? str
function page_result (line 29) | def page_result str
function pager (line 37) | def pager
FILE: lib/rib/extra/spring.rb
type Spring (line 3) | module Spring
type Commands (line 4) | module Commands
class Rib (line 5) | class Rib
method call (line 6) | def call
FILE: lib/rib/more/anchor.rb
type Rib (line 5) | module Rib; module Anchor
type Anchor (line 5) | module Anchor
function prompt (line 11) | def prompt
function anchor? (line 26) | def anchor?
function prompt_anchor (line 33) | def prompt_anchor
type Imp (line 42) | module Imp
function anchor (line 55) | def anchor obj_or_binding, opts={}
function stop_anchors (line 76) | def stop_anchors
FILE: lib/rib/more/beep.rb
type Rib (line 5) | module Rib; module Beep
type Beep (line 5) | module Beep
function loop_once (line 11) | def loop_once
function beep (line 19) | def beep
function beep_threshold (line 23) | def beep_threshold
FILE: lib/rib/more/bottomup_backtrace.rb
type Rib (line 5) | module Rib; module BottomupBacktrace
type BottomupBacktrace (line 5) | module BottomupBacktrace
function format_error (line 11) | def format_error err
function format_backtrace (line 17) | def format_backtrace backtrace
FILE: lib/rib/more/caller.rb
type Rib (line 5) | module Rib; module Caller
type Caller (line 5) | module Caller
type Imp (line 9) | module Imp
function caller (line 10) | def caller *filters
function display_backtrace (line 16) | def display_backtrace raw_backtrace, *filters
FILE: lib/rib/more/color.rb
type Rib (line 5) | module Rib; module Color
type Color (line 5) | module Color
function before_loop (line 11) | def before_loop
function format_result (line 16) | def format_result result
function get_error (line 21) | def get_error err
function warn (line 27) | def warn message
function colors (line 34) | def colors
function format_color (line 48) | def format_color result, display=inspect_result(result)
function format_backtrace (line 80) | def format_backtrace backtrace
function colorize_backtrace (line 87) | def colorize_backtrace backtrace
function find_color (line 101) | def find_color colors, value
function color (line 110) | def color rgb
function black (line 114) | def black █ color(30, &block); end
function red (line 115) | def red █ color(31, &block); end
function green (line 116) | def green █ color(32, &block); end
function yellow (line 117) | def yellow █ color(33, &block); end
function blue (line 118) | def blue █ color(34, &block); end
function magenta (line 119) | def magenta █ color(35, &block); end
function cyan (line 120) | def cyan █ color(36, &block); end
function white (line 121) | def white █ color(37, &block); end
function reset (line 122) | def reset █ color( 0, &block); end
FILE: lib/rib/more/edit.rb
type Rib (line 6) | module Rib; module Edit
type Edit (line 6) | module Edit
type Imp (line 10) | module Imp
function edit (line 11) | def edit
function editor (line 34) | def editor
FILE: lib/rib/more/multiline_history.rb
type Rib (line 6) | module Rib; module MultilineHistory
type MultilineHistory (line 6) | module MultilineHistory
function before_loop (line 12) | def before_loop
function loop_eval (line 17) | def loop_eval input
function handle_interrupt (line 25) | def handle_interrupt
function handle_multiline (line 37) | def handle_multiline
function multiline_trash (line 46) | def multiline_trash
FILE: lib/rib/more/multiline_history_file.rb
type Rib (line 5) | module Rib; module MultilineHistoryFile
type MultilineHistoryFile (line 5) | module MultilineHistoryFile
function before_loop (line 11) | def before_loop
function read_history (line 19) | def read_history
function write_history (line 35) | def write_history
function multiline_history_file_token (line 47) | def multiline_history_file_token
FILE: lib/rib/plugin.rb
type Rib (line 3) | module Rib; module Plugin
type Plugin (line 3) | module Plugin
function enable (line 6) | def enable
function disable (line 13) | def disable
function enabled? (line 20) | def enabled?
function disabled? (line 24) | def disabled?
function const_missing (line 29) | def const_missing mod
function extended (line 40) | def self.extended mod
FILE: lib/rib/runner.rb
type Rib (line 5) | module Rib; module Runner
type Runner (line 5) | module Runner
function options (line 7) | def options
function commands (line 35) | def commands
function command_paths (line 43) | def command_paths
function command_descriptions (line 53) | def command_descriptions
function command_descriptions_find (line 63) | def command_descriptions_find path
function run (line 69) | def run argv=ARGV
function loop (line 82) | def loop retry_times=5
function parse (line 100) | def parse argv
function parse_next (line 152) | def parse_next argv, arg
function help (line 156) | def help
function load_command (line 171) | def load_command command
function which_bin (line 185) | def which_bin bin # handle windows here
FILE: lib/rib/shell.rb
type Rib (line 6) | module Rib; class Shell
class Shell (line 6) | class Shell
method use (line 9) | def self.use mod
method initialize (line 38) | def initialize(config={})
method loop (line 48) | def loop
method start (line 63) | def start
method stop (line 67) | def stop
method running? (line 71) | def running?
method warnings (line 75) | def warnings
method set_trap (line 82) | def set_trap
method release_trap (line 86) | def release_trap
method new_private_binding (line 93) | def new_private_binding
FILE: lib/rib/test.rb
function shell (line 19) | def shell opts={}
function new_shell (line 23) | def new_shell opts={}
function stub_output (line 33) | def stub_output
function readline? (line 39) | def readline?
function stub_readline (line 44) | def stub_readline meth=:stub
function test_for (line 51) | def test_for *plugins, &block
function test_level1 (line 77) | def test_level1 rest, block
function test_level2 (line 89) | def test_level2 rest, block
function test_level3 (line 101) | def test_level3 rest, block
function main (line 121) | def main
FILE: lib/rib/test/history.rb
function tempfile (line 19) | def tempfile
function history_file (line 23) | def history_file
FILE: lib/rib/test/multiline.rb
function setup_input (line 4) | def setup_input str
function input (line 12) | def input str
function input_done (line 17) | def input_done str, err=nil
function check (line 28) | def check str, err=nil
FILE: lib/rib/version.rb
type Rib (line 3) | module Rib
FILE: test/core/test_history.rb
function read_history (line 34) | def read_history
function write_history (line 48) | def write_history
FILE: test/extra/test_autoindent.rb
function config (line 10) | def config
function stack_size (line 13) | def stack_size
function ri (line 28) | def ri input, size
function le (line 34) | def le input, size
FILE: test/more/test_anchor.rb
function anchor_deeper (line 36) | def anchor_deeper shell, index
function escape (line 48) | def escape shell
function mock_deeper (line 54) | def mock_deeper index
FILE: test/more/test_beep.rb
function verify (line 12) | def verify delay, threshold=nil, &block
function expect_beep (line 24) | def expect_beep sh
function unexpect_beep (line 28) | def unexpect_beep sh
FILE: test/more/test_color.rb
function colors (line 14) | def colors
function inspect_result (line 18) | def inspect_result result
FILE: test/more/test_multiline_history.rb
function check (line 10) | def check str, err=nil
function with_history (line 24) | def with_history str, err, *prefix
FILE: test/test_runner.rb
function input (line 12) | def input *args
function output (line 17) | def output *args
function verify_app_e (line 36) | def verify_app_e argv
FILE: test/test_shell.rb
function input (line 9) | def input str=Rib::Skip
function interrupt (line 40) | def interrupt
function input (line 54) | def input str=nil
Condensed preview — 71 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (147K chars).
[
{
"path": ".gitignore",
"chars": 17,
"preview": "/pkg/\n/coverage/\n"
},
{
"path": ".gitlab-ci.yml",
"chars": 660,
"preview": "\nstages:\n - test\n\n.test:\n stage: test\n image: ruby:${RUBY_VERSION}-bullseye\n variables:\n GIT_DEPTH: \"1\"\n GIT_S"
},
{
"path": ".gitmodules",
"chars": 76,
"preview": "[submodule \"task\"]\n\tpath = task\n\turl = https://github.com/godfat/gemgem.git\n"
},
{
"path": "CHANGES.md",
"chars": 13410,
"preview": "# CHANGES\n\n## Rib 1.6.2 -- 2026-01-20\n\n### Bugs fixed\n\n* [core/strip_backtrace] Now it works with backtrace quotes chang"
},
{
"path": "Gemfile",
"chars": 244,
"preview": "\nsource 'https://rubygems.org'\n\ngemspec\n\ngem 'rake'\ngem 'pork'\ngem 'muack'\n\ngem 'bond'\ngem 'hirb'\n\ngem 'simplecov', :req"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 14659,
"preview": "# Rib [](https://gitlab.com/godfat/rib/-/pip"
},
{
"path": "Rakefile",
"chars": 340,
"preview": "\nbegin\n require \"#{__dir__}/task/gemgem\"\nrescue LoadError\n sh 'git submodule update --init --recursive'\n exec Gem.rub"
},
{
"path": "TODO.md",
"chars": 613,
"preview": "# TODO\n\n* cleanup the tests. it's so messy right now\n\n* Runner tests\n* Documentation\n* Implement exception_spy\n\n<https:/"
},
{
"path": "asciicast.json",
"chars": 8345,
"preview": "{\n \"version\": 1,\n \"width\": 80,\n \"height\": 24,\n \"duration\": 31.5,\n \"command\": null,\n \"title\": \"rib\",\n \"env\": {\n "
},
{
"path": "bin/rib",
"chars": 94,
"preview": "#!/usr/bin/env ruby\n\nrequire 'rib/runner'\nRib.config[:mimic_irb] = true\nRib::Runner.run(ARGV)\n"
},
{
"path": "bin/rib-all",
"chars": 82,
"preview": "#!/usr/bin/env ruby\n\nrequire 'rib/runner'\nrequire 'rib/all'\nRib::Runner.run(ARGV)\n"
},
{
"path": "bin/rib-auto",
"chars": 375,
"preview": "#!/usr/bin/env ruby\n\nrequire 'rib/runner'\n# create the shell before app to prvent your bundler (if any) kicks in\nRib.she"
},
{
"path": "bin/rib-min",
"chars": 95,
"preview": "#!/usr/bin/env ruby\n\nrequire 'rib/runner'\nRib.config[:mimic_irb] = false\nRib::Runner.run(ARGV)\n"
},
{
"path": "bin/rib-rack",
"chars": 375,
"preview": "#!/usr/bin/env ruby\n\nrequire 'rib/runner'\n# create the shell before app to prvent your bundler (if any) kicks in\nRib.she"
},
{
"path": "bin/rib-rails",
"chars": 377,
"preview": "#!/usr/bin/env ruby\n\nrequire 'rib/runner'\n# create the shell before app to prvent your bundler (if any) kicks in\nRib.she"
},
{
"path": "lib/rib/all.rb",
"chars": 69,
"preview": "# frozen_string_literal: true\n\nrequire 'rib/core'\nrequire 'rib/more'\n"
},
{
"path": "lib/rib/api.rb",
"chars": 3527,
"preview": "# frozen_string_literal: true\n\nmodule Rib; module API\n # Called before shell starts looping\n def before_loop\n self\n"
},
{
"path": "lib/rib/app/auto.rb",
"chars": 497,
"preview": "# frozen_string_literal: true\n\nmodule Rib; module Auto\n module_function\n def load\n app, name = %w[rails rack].find{"
},
{
"path": "lib/rib/app/rack.rb",
"chars": 643,
"preview": "# frozen_string_literal: true\n\nmodule Rib; module Rack\n singleton_class.module_eval{ attr_accessor :app }\n\n module_fun"
},
{
"path": "lib/rib/app/rails.rb",
"chars": 3023,
"preview": "# frozen_string_literal: true\n\nmodule Rib; module Rails\n module_function\n def load\n load_rails\n rescue LoadError ="
},
{
"path": "lib/rib/config.rb",
"chars": 64,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\nRib.require_config\n"
},
{
"path": "lib/rib/core/completion.rb",
"chars": 812,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\n\nmodule Rib; module Completion\n extend Plugin\n Shell.use(self)\n\n # -----"
},
{
"path": "lib/rib/core/history.rb",
"chars": 1578,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\nrequire 'fileutils'\n\nmodule Rib; module History\n extend Plugin\n Shell.use"
},
{
"path": "lib/rib/core/last_value.rb",
"chars": 538,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\n\nmodule Rib; module LastValue\n extend Plugin\n Shell.use(self)\n\n attr_rea"
},
{
"path": "lib/rib/core/multiline.rb",
"chars": 4234,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\n\n# from https://github.com/janlelis/ripl-multi_line\nmodule Rib; module Mult"
},
{
"path": "lib/rib/core/readline.rb",
"chars": 501,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\nrequire 'readline'\n\nmodule Rib; module Readline\n extend Plugin\n Shell.use"
},
{
"path": "lib/rib/core/squeeze_history.rb",
"chars": 1024,
"preview": "# frozen_string_literal: true\n\nrequire 'rib/core/history' # dependency\n\nmodule Rib; module SqueezeHistory\n extend Plugi"
},
{
"path": "lib/rib/core/strip_backtrace.rb",
"chars": 1155,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\n\nmodule Rib; module StripBacktrace\n extend Plugin\n Shell.use(self)\n\n # -"
},
{
"path": "lib/rib/core.rb",
"chars": 347,
"preview": "# frozen_string_literal: true\n\n# before session starts\nrequire 'rib/core/completion'\n\n# upon session ends\nrequire 'rib/c"
},
{
"path": "lib/rib/debug.rb",
"chars": 153,
"preview": "# frozen_string_literal: true\n\nrequire 'rib/config'\nrequire 'rib/more/anchor'\nRib::Anchor.disable\nRib::Debugger.disable "
},
{
"path": "lib/rib/extra/autoindent.rb",
"chars": 4895,
"preview": "# frozen_string_literal: true\n\nrequire 'rib/core/history' # otherwise the order might be wrong\nrequire 'rib/core/readl"
},
{
"path": "lib/rib/extra/byebug.rb",
"chars": 1954,
"preview": "# frozen_string_literal: true\n\nrequire 'rib/more/anchor'\nrequire 'byebug/core'\n\n# This is based on lib/byebug/processors"
},
{
"path": "lib/rib/extra/hirb.rb",
"chars": 614,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\n\nmodule Rib; module Hirb\n extend Plugin\n Shell.use(self)\n\n # -----------"
},
{
"path": "lib/rib/extra/paging.rb",
"chars": 1323,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\n\nmodule Rib; module Paging\n extend Plugin\n Shell.use(self)\n\n # ---------"
},
{
"path": "lib/rib/extra/spring.rb",
"chars": 195,
"preview": "# frozen_string_literal: true\n\nmodule Spring\n module Commands\n class Rib\n def call\n load `which rib`.cho"
},
{
"path": "lib/rib/more/anchor.rb",
"chars": 2024,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\n\nmodule Rib; module Anchor\n extend Plugin\n Shell.use(self)\n\n # ---------"
},
{
"path": "lib/rib/more/beep.rb",
"chars": 433,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\n\nmodule Rib; module Beep\n extend Plugin\n Shell.use(self)\n\n # -----------"
},
{
"path": "lib/rib/more/bottomup_backtrace.rb",
"chars": 404,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\n\nmodule Rib; module BottomupBacktrace\n extend Plugin\n Shell.use(self)\n\n "
},
{
"path": "lib/rib/more/caller.rb",
"chars": 906,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\n\nmodule Rib; module Caller\n extend Plugin\n Shell.use(self)\n\n module Imp\n"
},
{
"path": "lib/rib/more/color.rb",
"chars": 4055,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\n\nmodule Rib; module Color\n extend Plugin\n Shell.use(self)\n\n # ----------"
},
{
"path": "lib/rib/more/edit.rb",
"chars": 666,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\nrequire 'tempfile'\n\nmodule Rib; module Edit\n extend Plugin\n Shell.use(sel"
},
{
"path": "lib/rib/more/multiline_history.rb",
"chars": 1026,
"preview": "# frozen_string_literal: true\n\nrequire 'rib/core/history' # dependency\nrequire 'rib/core/multiline' # dependency\n\nmodu"
},
{
"path": "lib/rib/more/multiline_history_file.rb",
"chars": 1204,
"preview": "# frozen_string_literal: true\n\nrequire 'rib/more/multiline_history'\n\nmodule Rib; module MultilineHistoryFile\n extend Pl"
},
{
"path": "lib/rib/more.rb",
"chars": 376,
"preview": "# frozen_string_literal: true\n\n# upon session ends\nrequire 'rib/more/multiline_history_file'\n\n# upon formatting output\nr"
},
{
"path": "lib/rib/plugin.rb",
"chars": 1356,
"preview": "# frozen_string_literal: true\n\nmodule Rib; module Plugin\n attr_accessor :disabled\n\n def enable\n self.disabled = fal"
},
{
"path": "lib/rib/runner.rb",
"chars": 5806,
"preview": "# frozen_string_literal: true\n\nrequire 'rib'\n\nmodule Rib; module Runner\n module_function\n def options\n @options ||="
},
{
"path": "lib/rib/shell.rb",
"chars": 2725,
"preview": "# frozen_string_literal: true\n\nrequire 'rib/plugin'\nrequire 'rib/api'\n\nmodule Rib; class Shell\n include API\n\n def self"
},
{
"path": "lib/rib/test/history.rb",
"chars": 370,
"preview": "# frozen_string_literal: true\n\nrequire 'tempfile'\n\ncopy :setup_history do\n before do\n if readline?\n ::Readline:"
},
{
"path": "lib/rib/test/multiline.rb",
"chars": 3062,
"preview": "# frozen_string_literal: true\n\ncopy :setup_multiline do\n def setup_input str\n if readline?\n stub_readline(:mock"
},
{
"path": "lib/rib/test.rb",
"chars": 2573,
"preview": "# frozen_string_literal: true\n\nrequire 'pork/auto'\nrequire 'muack'\n\nPork::Suite.include(Muack::API)\n\nrequire 'rib'\n\ncopy"
},
{
"path": "lib/rib/version.rb",
"chars": 66,
"preview": "# frozen_string_literal: true\n\nmodule Rib\n VERSION = '1.6.3'\nend\n"
},
{
"path": "lib/rib.rb",
"chars": 3927,
"preview": "# frozen_string_literal: true\n\nrequire 'rib/shell'\nrequire 'rib/version'\n\nmodule Rib\n Skip = Object.new\n\n module_funct"
},
{
"path": "rib.gemspec",
"chars": 4312,
"preview": "# -*- encoding: utf-8 -*-\n# stub: rib 1.6.3 ruby lib\n\nGem::Specification.new do |s|\n s.name = \"rib\".freeze\n s.version "
},
{
"path": "test/core/test_completion.rb",
"chars": 469,
"preview": "\nrequire 'rib/test'\nrequire 'rib/core/completion'\n\ndescribe Rib::Completion do\n paste :rib\n\n before do\n Rib::Comple"
},
{
"path": "test/core/test_history.rb",
"chars": 1390,
"preview": "\nrequire 'rib/test'\nrequire 'rib/test/history'\nrequire 'rib/core/history'\n\ndescribe Rib::History do\n paste :rib\n paste"
},
{
"path": "test/core/test_last_value.rb",
"chars": 680,
"preview": "\nrequire 'rib/test'\nrequire 'rib/core/last_value'\n\ndescribe Rib::LastValue do\n paste :rib\n\n before do\n stub_output\n"
},
{
"path": "test/core/test_multiline.rb",
"chars": 205,
"preview": "\nrequire 'rib/test'\nrequire 'rib/test/multiline'\nrequire 'rib/core/multiline'\n\ndescribe Rib::Multiline do\n paste :rib\n "
},
{
"path": "test/core/test_readline.rb",
"chars": 381,
"preview": "\nrequire 'rib/test'\nrequire 'rib/core/readline'\n\ndescribe Rib::Readline do\n paste :rib\n\n test_for Rib::Readline do\n "
},
{
"path": "test/core/test_squeeze_history.rb",
"chars": 1060,
"preview": "\nrequire 'rib/test'\nrequire 'rib/test/history'\nrequire 'rib/core/squeeze_history'\n\ndescribe Rib::SqueezeHistory do\n pas"
},
{
"path": "test/core/test_strip_backtrace.rb",
"chars": 519,
"preview": "\nrequire 'rib/test'\nrequire 'rib/core/strip_backtrace'\n\ndescribe Rib::StripBacktrace do\n would 'strip home' do\n back"
},
{
"path": "test/extra/test_autoindent.rb",
"chars": 4561,
"preview": "\nrequire 'rib/test'\nrequire 'rib/extra/autoindent'\n\ndescribe Rib::Autoindent do\n paste :rib\n\n autoindent = Class.new d"
},
{
"path": "test/more/test_anchor.rb",
"chars": 1553,
"preview": "\nrequire 'rib/test'\nrequire 'rib/more/anchor'\nrequire 'rib/core/multiline'\nrequire 'rib/test/multiline'\n\ndescribe Rib::A"
},
{
"path": "test/more/test_beep.rb",
"chars": 907,
"preview": "\nrequire 'rib/test'\nrequire 'rib/more/beep'\n\ndescribe Rib::Beep do\n paste :rib\n\n before do\n Rib::Beep.enable\n end\n"
},
{
"path": "test/more/test_caller.rb",
"chars": 229,
"preview": "\nrequire 'rib/test'\nrequire 'rib/more/caller'\n\ndescribe Rib::Caller do\n paste :rib\n\n test_for Rib::Caller do\n would"
},
{
"path": "test/more/test_color.rb",
"chars": 1886,
"preview": "\nrequire 'rib/test'\nrequire 'rib/more/color'\n\ndescribe Rib::Color do\n paste :rib\n\n before do\n Rib::Color.enable\n e"
},
{
"path": "test/more/test_multiline_history.rb",
"chars": 1004,
"preview": "\nrequire 'rib/test'\nrequire 'rib/test/multiline'\nrequire 'rib/more/multiline_history'\n\ndescribe Rib::MultilineHistory do"
},
{
"path": "test/test_api.rb",
"chars": 1153,
"preview": "\nrequire 'rib/test'\nrequire 'rib/shell'\n\ndescribe Rib::API do\n paste :rib\n\n Rib::API.instance_methods.delete_if{ |e| e"
},
{
"path": "test/test_plugin.rb",
"chars": 1256,
"preview": "\nrequire 'rib/test'\nrequire 'rib/all'\n\ndescribe Rib::Plugin do\n paste :rib\n\n before do\n @names = Dir[File.expand_pa"
},
{
"path": "test/test_runner.rb",
"chars": 961,
"preview": "\nrequire 'rib/test'\nrequire 'rib/runner'\n\ndescribe Rib::Runner do\n paste :rib\n\n before do\n mock(Rib).shell{ shell }"
},
{
"path": "test/test_shell.rb",
"chars": 4265,
"preview": "\nrequire 'rib/test'\nrequire 'rib/shell'\n\ndescribe Rib::Shell do\n paste :rib\n\n describe '#loop' do\n def input str=Ri"
}
]
About this extraction
This page contains the full source code of the godfat/rib GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 71 files (132.8 KB), approximately 40.1k tokens, and a symbol index with 291 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.