require
Remove leading directory components from a path, like tar's --strip-components option
OS-dependent application paths for cache, data and config directories
Nested/recursive `.gitignore`/`.npmignore` parsing and filtering.
A tiny (381B to 419B) utility to make a directory and its parents, recursively
Cli tools for napi-rs
Koa static file resolver, dirs, default index, path replace, cache, livereload, gzip
Export directories and their files as node.js modules.
Webpack Virtual Modules
Get cross-platform XDG Base Directories or their equivalents. Works with Linux, Windows (win32), or MacOS (darwin).
chdir in chainer fashion + read file
return all the parent directories for a directory
Nuxt Module for pinia
egg typescript helper
loop through commands in fun and amazing ways!
Get the path of user-specific directories
extra-watch-webpack-plugin would help you to attach extra files or dirs to webpack's watch system
A tiny library with a minimal API that provides the platform-specific, user-accessible locations for retrieving and storing configuration
A collection of commonly used functions for manipulating the filesystem
node module to synchronously and recursively merge files from one folder to another
Simple, clean application directory resolution
Copy file globs, watching for changes.
Recursively walks parent folders looking for a config file
list of all subdirectories
By adding a .base file to your application base dir, helps you augment $LOAD_PATH, auto-require files, and set constants to important paths.
Easily and non-intrusively require files from sub-folders. Without polluting global namespace, or having modules clobber each other, include RequireDir and initialize it to get access to #dir and #dir_r
By adding a .base file to your application base dir, helps you augment $LOAD_PATH, auto-require files, and set constants to important paths.
Create dump file in temporary folder of root directory, if folder not present in dir then it will create one. Usage: open interactive prompt by typing 'irb' and require 'generate_dump_file'. again, require File.expand_path('../config/environment', __FILE__) and then run GenerateDumpFile.create
Gem to interact with the Rls.io/u url shortner and /p/ paste filecontent gem. Usage: require 'rlsgem' Rlsgem.cut('http://www.too.long.url/and/sub/dirs') or Rlsgem.paste_file('Paste title','/path/of/file/to/paste')
Required is a utility to require all files in a directory. Why would one want to require a whole bunch of files at once? I have used this gem on 2 projects to: - require dozens of jar files when working on a JRuby project - pull in all files before running code coverage (rcov), to find code that is otherwise dead/untouched Options for required include the ability to recursively descend through subdirectories, include/exclude files based on pattern matching, and to specify the order of requires based on filename. An array of all the files that were loaded is returned. Quick example: require 'required' required "some/path/to/dir" See the README for more examples, and description of options.
OCRAN (One-Click Ruby Application Next) packages Ruby applications for distribution. It bundles your script, the Ruby interpreter, gems, and native libraries into a self-contained artifact that runs without requiring Ruby to be installed on the target machine. Three output formats are supported on all platforms: - Self-extracting executable (.exe on Windows, native binary on Linux/macOS) - Directory with a launch script (--output-dir) - Zip archive with a launch script (--output-zip) This is a fork of OCRA maintained for Ruby 3.2+ compatibility. Migration guide: replace OCRA_EXECUTABLE with OCRAN_EXECUTABLE in your code. Usage: ocran helloworld.rb # builds helloworld.exe / helloworld ocran --output-dir out/ app.rb ocran --output-zip app.zip app.rb See readme at https://github.com/largo/ocran Report problems at https://github.com/largo/ocran/issues
pikuri-assistant ships the demo +bin/pikuri-assistant+ binary on top of pikuri-core + pikuri-skills + pikuri-mcp: an interactive chat agent the user hand-edits to declare a +Pikuri::Mcp::Registry+ of MCP servers. The +Pikuri.prompt+ search path picks up this gem's +prompts/pikuri-assistant.txt+ automatically on require — same multi-gem prompt-dir pattern as pikuri-code.
= Mcrypt - libmcrypt bindings for Ruby Mcrypt provides Ruby-language bindings for libmcrypt(3), a symmetric cryptography library. {Libmcrypt}[http://mcrypt.sourceforge.net/] supports lots of different ciphers and encryption modes. == You will need * A working Ruby installation (>= 1.8.6 or 1.9) * A working libmcrypt installation (2.5.x or 2.6.x, tested with 2.5.8) * A sane build environment == Installation Install the gem: gem install ruby-mcrypt --test -- --with-mcrypt-dir=/path/to/mcrypt/prefix If you're installing on Ubuntu: sudo apt-get install mcrypt libmcrypt-dev gem install ruby-mcrypt If you want to run the longer test suite, do this instead: MCRYPT_TEST_BRUTE=1 \ gem install ruby-mcrypt --test -- --with-mcrypt-dir=/path/to/mcrypt/prefix Put this in your code: require 'rubygems' require 'mcrypt' Or in Rails' environment.rb: gem "ruby-mcrypt", :lib => "mcrypt" == Usage crypto = Mcrypt.new(:twofish, :cbc, MY_KEY, MY_IV, :pkcs) # encryption and decryption in one step ciphertext = crypto.encrypt(plaintext) plaintext = crypto.decrypt(ciphertext) # encrypt in smaller steps while chunk = $stdin.read(4096) $stdout << crypto.encrypt_more(chunk) end $stdout << crypto.encrypt_finish # or decrypt: while chunk = $stdin.read(4096) $stdout << crypto.decrypt_more(chunk) end $stdout << crypto.decrypt_finish == Known Issues * Test coverage is lacking. If you find any bugs, please let the author know. == Wish List * IO-like behavior, e.g. crypto.open($stdin) { |stream| ... } == Author * Philip Garrett <philgarr at gmail.com> == Copyright and License Copyright (c) 2009-2013 Philip Garrett. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Otto AsciiDoc-powered static site generator with Jekyll-style conventions: layouts, includes, data files, posts, drafts, permalinks, and custom collections. ## Install ```sh gem install ottogen ``` Requires Ruby 3.0 or newer. ## Quickstart ```sh mkdir mysite && cd mysite otto init otto build otto serve open http://127.0.0.1:8778/ ``` For a longer walkthrough including AsciiDoc syntax, see [GUIDE.md](GUIDE.md). ## Commands | Command | Description | |---|---| | `otto init [DIR]` | Scaffold a new site (current dir if omitted) | | `otto build` | Render the site to `_build/` | | `otto build --drafts` | Include posts from `_drafts/` | | `otto watch` | Rebuild on file change | | `otto serve` | Serve `_build/` on port 8778 | | `otto generate PAGE` | Create a new page in `pages/` | | `otto post "Title"` | Create a new dated post in `_posts/` | | `otto clean` | Delete `_build/` | | `otto doctor` | Sanity-check project layout | ## Project layout ``` my-site/ ├── .otto # marker ├── config.yml # site config ├── assets/ # copied verbatim into _build/ ├── pages/ # AsciiDoc pages, output mirrors path ├── _layouts/ # ERB layouts (.html.erb) ├── _includes/ # ERB partials ├── _data/ # YAML/JSON files exposed as site.data.* ├── _posts/ # YYYY-MM-DD-slug.adoc └── _drafts/ # undated drafts (excluded by default) ``` ## Configuration (`config.yml`) ```yaml title: My Otto Site description: Things I write url: https://example.com baseurl: "" permalink: /:year/:month/:day/:slug/ collections: recipes: output: true ``` `permalink` accepts these tokens: `:year`, `:month`, `:day`, `:slug`, `:title`. Templates ending in `/` produce pretty URLs (`<path>/index.html`). ## Pages and posts Both support YAML front matter: ```adoc --- layout: default title: Hello tags: [ruby, cli] --- = Hello Welcome to {site_title}. This page is at {page_url}. ``` Pages live under `pages/`; posts under `_posts/` with `YYYY-MM-DD-slug.adoc` names. Layouts wrap rendered AsciiDoc; partials in `_includes/` are pulled in via `<%= partial 'header.html' %>`. ## License MIT
# Noty A bookmarks and snippets manager, stores bookmarks as YAML files and nippets as plain text, utilizes "Ag silver searcher" fast search to search your files when you need to open or copy a snippet, that makes its searching capabilities so enourmouse as it's inherited from AG. Noty is smart, so it react depending on your input, so provide URL and it'll create a bookmark, provide some text and it will search for it in all bookmarks and snippets, if it didn't find any files it will prompt you to create a snippet. Some common usages could be, bookmarking URL, save snippet of text you liked, save some canned responses and quickly copy it when needed. ## Installation ```bash $ gem install noty ``` ## Requirements 1. ag : silver searcher https://github.com/ggreer/the_silver_searcher ### For Linux: 1. xsel : could be found on most distros official repositories 2. xdg-open : should be installed with most opendesktop compatible desktop environments ## Environment by default Noty saves your files in `~/.notes` if you want to change that path, define an Environment variable in your shell init file `.bashrc` or `.zshrc` ```bash export NOTES_PATH=/path/to/your/notes/dir ``` ## Usage Snippets and bookmarks manager. **Usage:** ```bash noty inputs ``` **Input types:** 1. **url:** e.g "http://www.example.com", add URL as a bookmark file 2. **keyword:** search bookmarks and perform action on it, a single word of multiple words or regex, it is passed to "ag silver searcher" 3. **snippet text:** any multiword text, it will search first if no files contain this text you'll be asked if you want to create a snippet for it ## Examples Add a bookmark ```bash noty https://www.youtube.com ``` Search for bookmark ```bash noty youtube ``` Add a snippet text ```bash noty this is a long text that I need to save in my stash ``` Search for a snippet (same as searching for bookmarks) ```bash noty need ``` ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/blazeeboy/noty. ## License The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
== Confidently Build Terminal Apps Rooibos[https://rooibos.run] helps you build interactive terminal applications. Keep your code understandable and testable as it scales. Rooibos handles keyboard, mouse, and async work so you can focus on behavior and user experience. gem install rooibos <i>Currently in beta. APIs may change before 1.0.</i> === Get Started in Seconds rooibos new my_app cd my_app rooibos run That's it. You have a working app with keyboard navigation, mouse support, and clickable buttons. Open <tt>lib/my_app.rb</tt> to make it your own. --- === The Pattern \Rooibos uses Model-View-Update, the architecture behind Elm[https://guide.elm-lang.org/architecture/], Redux[https://redux.js.org/], and {Bubble Tea}[https://github.com/charmbracelet/bubbletea]. State lives in one place. Updates flow in one direction. The runtime handles rendering and runs background work for you. --- === Hello, MVU The simplest \Rooibos app. Press any key to increment the counter. Press <tt>Ctrl</tt>+<tt>C</tt> to quit. require "rooibos" module Counter # Init: How do you create the initial model? Init = -> { 0 } # View: What does the user see? View = -> (model, tui) { tui.paragraph(text: <<~END) } Current count: #{model}. Press any key to increment. Press Ctrl+C to quit. END # Update: What happens when things change? Update = -> (message, model) { if message.ctrl_c? Rooibos::Command.exit elsif message.key? model + 1 end } end Rooibos.run(Counter) That's the whole pattern: Model holds state, Init creates it, View renders it, and Update changes it. The runtime handles everything else. --- === Your First Real Application A file browser in sixty lines. It opens files, navigates directories, handles errors, styles directories and hidden files differently, and supports vim-style keyboard shortcuts. If you can do this much with this little code, imagine how easy _your_ app will be to build. require "rooibos" module FileBrowser # Model: What state does your app need? Model = Data.define(:path, :entries, :selected, :error) Init = -> { path = Dir.pwd entries = Entries[path] Ractor.make_shareable( # Ensures thread safety Model.new(path:, entries:, selected: entries.first, error: nil)) } View = -> (model, tui) { tui.block( titles: [model.error || model.path, { content: KEYS, position: :bottom, alignment: :right}], borders: [:all], border_style: if model.error then tui.style(fg: :red) else nil end, children: [tui.list(items: model.entries.map(&ListItem[model, tui]), selected_index: model.entries.index(model.selected), highlight_symbol: "", highlight_style: tui.style(modifiers: [:reversed]))] ) } Update = -> (message, model) { return model.with(error: ERROR) if message.error? model = model.with(error: nil) if model.error && message.key? if message.ctrl_c? || message.q? then Rooibos::Command.exit elsif message.home? || message.g? then model.with(selected: model.entries.first) elsif message.end? || message.G? then model.with(selected: model.entries.last) elsif message.up_arrow? || message.k? then Select[:-, model] elsif message.down_arrow? || message.j? then Select[:+, model] elsif message.enter? then Open[model] elsif message.escape? then Navigate[File.dirname(model.path), model] end } private # Lines below this are implementation details KEYS = "↑/↓/Home/End: Select | Enter: Open | Esc: Navigate Up | q: Quit" ERROR = "Sorry, opening the selected file failed." ListItem = -> (model, tui) { -> (name) { modifiers = name.start_with?(".") ? [:dim] : [] fg = :blue if name.end_with?("/") tui.list_item(content: name, style: tui.style(fg:, modifiers:)) } } Select = -> (operator, model) { new_index = model.entries.index(model.selected).public_send(operator, 1) model.with(selected: model.entries[new_index.clamp(0, model.entries.length - 1)]) } Open = -> (model) { full = File.join(model.path, model.selected.delete_suffix("/")) model.selected.end_with?("/") ? Navigate[full, model] : Rooibos::Command.open(full) } Navigate = -> (path, model) { entries = Entries[path] model.with(path:, entries:, selected: entries.first, error: nil) } Entries = -> (path) { Dir.children(path).map { |name| File.directory?(File.join(path, name)) ? "#{name}/" : name }.sort_by { |name| [name.end_with?("/") ? 0 : 1, name.downcase] } } end Rooibos.run(FileBrowser) --- === Batteries Included ==== Commands Applications fetch data, run shell commands, and set timers. \Rooibos Commands run off the main thread and send results back as messages. <b>HTTP requests:</b> Update = -> (message, model) { case message in :fetch_users [model.with(loading: true), Rooibos::Command.http(:get, "/api/users", :got_users)] in { type: :http, envelope: :got_users, status: 200, body: } model.with(loading: false, users: JSON.parse(body)) in { type: :http, envelope: :got_users, status: } model.with(error: "HTTP #{status}") end } <b>Shell commands:</b> Update = -> (message, model) { case message in :list_files Rooibos::Command.system("ls -la", :listed_files) in { type: :system, envelope: :listed_files, stdout:, status: 0 } model.with(files: stdout.lines.map(&:chomp)) in { type: :system, envelope: :listed_files, stderr:, status: } model.with(error: stderr) end } <b>Timers:</b> Update = -> (message, model) { case message in { type: :timer, envelope: :tick, elapsed: } [model.with(frame: model.frame + 1), Rooibos::Command.wait(1.0 / 24, :tick)] end } <b>And more!</b> \Rooibos includes <tt>all</tt>, <tt>batch</tt>, <tt>bubble</tt>, <tt>cancel</tt>, <tt>custom</tt>, <tt>deliver</tt>, <tt>exit</tt>, <tt>http</tt>, <tt>map</tt>, <tt>open</tt>, <tt>system</tt>, <tt>tick</tt>, and <tt>wait</tt> commands. You can also define your own custom commands for complex orchestration. Every command produces a message, and Update handles it the same way. ==== Testing \Rooibos makes TUIs so easy to test, you'll save more time by writing tests than by not testing. <b>Unit test Update, View, and Init.</b> No terminal needed. Test helpers included. def test_moves_selection_down_with_j model = Ractor.make_shareable(FileBrowser::Model.new( path: "/", entries: %w[bin exe lib], selected: "bin", error: nil)) message = RatatuiRuby::Event::Key.new(code: "j") result = FileBrowser::Update.call(message, model) assert_equal "exe", result.selected end <b>Style assertions.</b> Draw to a headless terminal, verify colors and modifiers. def test_directories_are_blue with_test_terminal(60, 10) do model = Ractor.make_shareable(FileBrowser::Model.new( path: "/", entries: %w[file.txt subdir/], selected: "file.txt", error: nil)) widget = FileBrowser::View.call(model, RatatuiRuby::TUI.new) RatatuiRuby.draw { |frame| frame.render_widget(widget, frame.area) } assert_blue(1, 2) # "subdir/" at column 1, row 2 end end <b>System tests.</b> Inject events, run the full app, snapshot the result. def test_selection_moves_down with_test_terminal(120, 30) do Dir.mktmpdir do |dir| FileUtils.touch(File.join(dir, "a")) FileUtils.touch(File.join(dir, "b")) FileUtils.touch(File.join(dir, "c")) inject_key(:down) inject_key(:ctrl_c) # Tests use explicit params to inject deterministic initial state. Rooibos.run( model: Ractor.make_shareable(FileBrowser::Model.new( path: dir, entries: %w[a b c], selected: "a", error: nil)), view: FileBrowser::View, update: FileBrowser::Update ) assert_snapshots("selection_moved_down") do |lines| title = "┌/tmp/test#{'─' * 107}┐" lines.map do |l| l.gsub(/┌#{Regexp.escape(dir)}[^┐]*┐/, title) end end end end end Snapshots record both plain text and ANSI colors. Normalization blocks mask dynamic content (timestamps, temp paths) for cross-platform reproducibility. Run <tt>UPDATE_SNAPSHOTS=1 rake test</tt> to regenerate baselines. ==== Scale Up Large applications decompose into fragments. Each fragment has its own Model, View, Update, and Init. Parents compose children. The pattern scales. The Router DSL eliminates boilerplate: module Dashboard include Rooibos::Router route :stats, to: StatsPanel route :network, to: NetworkPanel receive_events :ctrl_c, -> { Rooibos::Command.exit } only when: -> (_message, model) { !model.modal_open } do receive_events :q, -> { Rooibos::Command.exit } forward_events :s, to: :stats, as: :fetch forward_events :p, to: :network, as: :ping end Update = from_router # ... Model, Init, View below end Declare routes and event handlers. The router generates Update for you. Use guards to ignore messages when needed. ==== CLI The <tt>rooibos</tt> command scaffolds projects and runs applications. rooibos new my_app # Generate project structure rooibos run # Run the app in current directory Generated apps include tests, type signatures, and a working welcome screen with keyboard and mouse support. --- === The Ecosystem \Rooibos builds on RatatuiRuby[https://www.ratatui-ruby.dev], a Rubygem built on Ratatui[https://ratatui.rs]. You get native performance with the joy of Ruby. \Rooibos is one way to manage state and composition. Kit is another. ==== Rooibos[https://www.rooibos.run] Model-View-Update architecture. Inspired by Elm, Bubble Tea, and React + Redux. Your UI is a pure function of state. - Functional programming with MVU - Commands work off the main thread - Messages, not callbacks, drive updates ==== {Kit}[https://sr.ht/~kerrick/ratatui_ruby/#chapter-3-the-object-path--kit] (Coming Soon) Component-based architecture. Encapsulate state, input handling, and rendering in reusable pieces. - OOP with stateful components - Separate UI state from domain logic - Built-in focus management & click handling Both use the same widget library and rendering engine. Pick the paradigm that fits your brain. --- === Links [Get Started] {Getting Started}[https://www.rooibos.run/docs/trunk/doc/getting_started/index_md.html], {Tutorial}[https://www.rooibos.run/docs/trunk/doc/tutorial/index_md.html], {Examples}[https://www.rooibos.run/docs/trunk/examples/app_fractal_dashboard/README_md.html] [Coming From...] {React/Redux}[https://www.rooibos.run/docs/trunk/doc/getting_started/for_react_developers_md.html], {BubbleTea}[https://www.rooibos.run/docs/trunk/doc/getting_started/for_go_developers_md.html], {Textual}[https://www.rooibos.run/docs/trunk/doc/getting_started/for_python_developers_md.html] [Learn More] {Essentials}[https://www.rooibos.run/docs/trunk/doc/essentials/index_md.html], {Scaling Up}[https://www.rooibos.run/docs/trunk/doc/scaling_up/index_md.html], {Best Practices}[https://www.rooibos.run/docs/trunk/doc/best_practices/index_md.html], {Troubleshooting}[https://www.rooibos.run/docs/trunk/doc/troubleshooting/index_md.html] [Community] {Forum}[https://forum.setdef.com/c/rooibos], {Announcements}[https://forum.setdef.com/tags/c/rooibos/announcement], {Bug Tracker}[https://forum.setdef.com/tags/c/rooibos/bug], {Contribution Guide}[https://github.com/setdef/Rooibos/blob/trunk/CONTRIBUTING.md], {Code of Conduct}[https://github.com/setdef/Rooibos/blob/trunk/CODE_OF_CONDUCT.md] --- [Website] https://rooibos.run [Source] https://github.com/setdef/Rooibos [RubyGems] https://rubygems.org/gems/rooibos © 2026 Kerrick Long · Library: LGPL-3.0-or-later · Website: CC-BY-NC-ND-4.0 · Snippets: MIT-0