From b2e1089dd49459c31cb3b0400f7dab1442892b23 Mon Sep 17 00:00:00 2001 From: Thomas Sawyer Date: Sun, 27 Sep 2026 14:41:57 -0400 Subject: [PATCH] docs: modernize README and website :doc: --- README.md | 269 ++------- docs/README.md | 11 + .../2008-01-01-how-facets-was-born.html | 16 + docs/_src/archive/2008-03-24-release-2-4.html | 57 ++ docs/_src/archive/2009-07-21-new-website.html | 8 + docs/_src/archive/2009-08-22-release-2-7.html | 122 ++++ docs/_src/archive/2009-11-09-release-2-8.html | 62 ++ docs/_src/archive/2010-09-01-release-2-9.html | 28 + docs/_src/index.erb | 55 ++ docs/_src/layout.erb | 45 ++ docs/_src/learn.erb | 24 + docs/_src/news.erb | 7 + docs/_src/source.erb | 7 + docs/assets/images/cherries.svg | 8 + docs/assets/styles/site.css | 565 ++++++++---------- docs/atom.xml | 86 +-- docs/build.rb | 55 ++ docs/index.html | 267 +++------ docs/learn.html | 237 ++------ docs/news.html | 302 ++-------- .../posts/2008-01-01-how-facets-was-born.html | 162 ++--- docs/posts/2008-03-24-release-2-4.html | 164 ++--- docs/posts/2009-07-21-new-website.html | 164 ++--- docs/posts/2009-08-22-release-2-7.html | 164 ++--- docs/posts/2009-11-09-release-2-8.html | 164 ++--- docs/posts/2010-09-01-release-2-9.html | 162 ++--- docs/source.html | 182 ++---- 27 files changed, 1325 insertions(+), 2068 deletions(-) create mode 100644 docs/README.md create mode 100644 docs/_src/archive/2008-01-01-how-facets-was-born.html create mode 100644 docs/_src/archive/2008-03-24-release-2-4.html create mode 100644 docs/_src/archive/2009-07-21-new-website.html create mode 100644 docs/_src/archive/2009-08-22-release-2-7.html create mode 100644 docs/_src/archive/2009-11-09-release-2-8.html create mode 100644 docs/_src/archive/2010-09-01-release-2-9.html create mode 100644 docs/_src/index.erb create mode 100644 docs/_src/layout.erb create mode 100644 docs/_src/learn.erb create mode 100644 docs/_src/news.erb create mode 100644 docs/_src/source.erb create mode 100644 docs/assets/images/cherries.svg create mode 100644 docs/build.rb diff --git a/README.md b/README.md index 050a676f2..29fca0b07 100644 --- a/README.md +++ b/README.md @@ -1,253 +1,84 @@ -# Ruby Facets +# Ruby Facets cherries [![Gem Version](https://badge.fury.io/rb/facets.svg)](https://rubygems.org/gems/facets) [![CI](https://github.com/rubyworks/facets/actions/workflows/ci.yml/badge.svg)](https://github.com/rubyworks/facets/actions/workflows/ci.yml) +**More of Ruby, one method at a time.** Facets is a collection of extensions to Ruby's core classes and standard library, plus a few small, reusable classes and modules. Most methods live in their own files, so you can load one extension, a class's extensions, or the core collection. -*"ALL YOUR BASE ARE BELONG TO RUBY"* +Facets began in 2005 and is still maintained. The current release is **3.2.2**, which requires **Ruby 3.1 or newer**. See the [release history](HISTORY.md) for changes and migration notes from earlier versions. The `main` branch also contains changes awaiting the next release. +## Install -## Introduction +```sh +gem install facets +``` -Ruby Facets is the premier collection of general purpose method -extensions and standard additions for the Ruby programming language. +With Bundler, add this to your Gemfile: -Facets houses the largest single collection of methods available for -extending the core capabilities of Ruby's built-in classes and modules. -This collection of extension methods are unique by virtue of their atomicity. -The methods are stored in individual files so that each can be required -independently. This gives developers the potential for much finer control over -which extra methods to bring into their code. +```ruby +gem 'facets', require: false +``` -In addition Facets provides a collection of extensions to Ruby standard library -plus a small collection of add-on classes and modules. Together these -libraries constitute an reliable source of reusable components, suitable -to a wide variety of usecases. +`require: false` lets you choose which extensions to load. Omit it if you want Bundler to load the core collection automatically. +## Choose how much to load -## Resources +### One method -* Homepage: https://rubyworks.github.io/facets -* Report Bugs: https://github.com/rubyworks/facets/issues -* Wiki Pages: https://github.com/rubyworks/facets/wiki -* Source Code: https://github.com/rubyworks/facets +```ruby +require 'facets/array/to_ranges' +[1, 2, 3, 6, 7].to_ranges +#=> [1..3, 6..7] +``` -## Documentation - -Facets has special documentation needs due to its extensive breadth. -The documentation generated when installing via RubyGems, or the YARD -docs provided by rubydoc.info can be somewhat unwieldy because it -combines all of Facets in one large set. When using these resources, -it is important to remain aware of the source location of particular -methods. - -For better organized online documentation, generated to separate core -extensions from standard libraries, see the [Learn Facets](https://rubyworks.github.io/facets/learn.html) page on the website for links to available documentation. - - -## Installation - -### Bundler - -If you are using Bundler with your project, add the facets gem to the project's -Gemfile. Unless you want all of facets loaded be sure to add the `:require => false` -option. - - gem "facets", require: false - -### RubyGems - -The easiest way to install is via RubyGems. - - $ gem install facets - -### Requirements - -Facets 3.2+ requires Ruby 3.1 or higher. - - -## Mission - -Facets holds to the notion that the more we can *reasonably* integrate into -a common foundation, directed toward general needs, the better that foundation -will be able to serve the community. There are a number of advantages here: - -* Better Code-reuse -* Collaborative Improvements -* Greater Name Consistency -* One-stop Shop and Installation - - -## Usage - -### CORE Library - -At the heart of Ruby Facets is the CORE extensions library. CORE provides -a sizable collection of generally useful methods, along with a few supporting -classes, that extend the functionality of Ruby's core classes and modules. - -With the exception of a few *uncommon* extensions, CORE contains anything that -will load automatically when issuing: - - require 'facets' - -This loads all the CORE functionality at once. If you plan to use more then a -handful of Facets core methods it is recommended that you require the library in -this way. However, you can also "cherry pick" the CORE library as you prefer. -And for uncommon extensions this must be done. The general require statement for -a core extension library is: - - require 'facets//' - -For example: - - require 'facets/time/stamp' - -Most "atoms" contain only one method, but exceptions occur when methods -are closely tied together. +### One class's core extensions -You can load per-class or per-module groups of core methods by requiring the -class or module by name. For example" +```ruby +require 'facets/string' - require 'facets/time' +'Ruby Facets'.snakecase +#=> "ruby_facets" +``` -Will require all the core Time method extensions. +### The core collection -Note that some methods that were part of CORE in 1.8 and earlier are now part -of MORE libraries. A good example is 'random.rb'. There were separated because -they had more specialized use cases, where as CORE extensions are intended as -general purpose. +```ruby +require 'facets' -#### Method File Names +[1, 2, 3].average +#=> 2.0 +``` -Operator method redirect files are stored using English names. For instance -`Proc#*` is `proc/op_mul`. +`require 'facets'` loads the broadly useful **core** extensions. Some specialized core extensions are opt-in; require their method file directly. To load Facets extensions to a Ruby standard library, require that library through Facets: -For reference, here is the chart. +```ruby +require 'facets/ostruct' +``` - +@ => op_plus - -@ => op_minus - + => op_add - - => op_sub - ** => op_pow - * => op_mul - / => op_div - % => op_mod - ~ => op_tilde - <=> => op_cmp - << => op_lshift - >> => op_rshift - < => op_lt - > => op_gt - === => op_case - == => op_equal - =~ => op_apply - <= => op_lt_eq - >= => op_gt_eq - | => op_or - & => op_and - ^ => op_xor - []= => op_store - [] => op_fetch +This loads `ostruct` and Facets' OpenStruct extensions. On Ruby 3.5+, declare the `ostruct` gem separately because it is no longer a default gem. -Facets simply takes the '*' and translates it into a string acceptable to all -file systems. Also, if a method ends in '=', '?' or '!' it is simply removed. - - -### MORE Library (aka Standard Library) - -On top of the extensive CORE library, Facets provides extensions for Ruby's -standard library, as well as a small collection of additional modules and -classes to supplement it. - -Use this library like you would any other 3rd party library. -The only difference between Facet's Standard library and other libraries -is the lack of any enclosing `Facets::` namespace. - -When using Facets extended versions of Ruby's standard libraries, -the libraries have to loaded individually. However you do not need -to load Ruby's library first, as the Facets' library will do that -automatically. - -For example, normally one load Ruby's OpenStruct class via: - - require 'ostruct' - -To load 'ostruct.rb' plus Facets extensions for it simply use: - - require 'facets/ostruct' +## Documentation -For details pertaining to the functionality of each feature, -please see the API documentation. +- [Getting started and loading guide](https://rubyworks.github.io/facets/learn.html) +- [Generated API documentation on RubyDoc.info](https://www.rubydoc.info/gems/facets) (check the displayed version) +- [Release history](HISTORY.md) +In the published 3.2.2 gem, the split between `lib/core` and `lib/standard` is visible in API source paths. This helps you tell whether a method is loaded by `require 'facets'` or needs an explicit require. The development branch also has a new `lib/rails` area for Rails-compatible helpers; see the **Unreleased** section of the release history for details. ## Contribute -This project thrives on contribution! - -If you have any extension methods, classes or modules that you think have -very general applicability and would like to see them included in -this project, don't hesitate to submit. Also, if you have better versions -of any thing already included or simply have a patch, they are more than -welcome. We want Ruby Facets to be of the highest quality. - - -## Development - -Facets uses the [Lemon](https://rubyworks.github.io/lemon) testing framework -to handle unit testing, while [QED](https://rubyworks.github.io/qed) specifications -provide tested documentation. Run the test suite with [Rake](https://ruby.github.io/rake/): - - $ rake test - -Continuous integration runs on GitHub Actions (see `.github/workflows/ci.yml`). - - -## Authors - -Much of this collection was written and/or inspired by a variety of great Ruby -developers. Fortunately nearly all utilized works were copyrighted under the same -open licenses, the Ruby License or the more liberal BSD and MIT licenses. In the -one or two exceptions the copyright notice has been included with the source code. -We have since received permission from the various authors to normalize the licensing -to a single license. For this purpose we have chosen the BSD 2 Clause License. -This is the license Ruby itself now uses, so it seemed the most appropriate choice. -It is also almost identical to the MIT license. Any code file not specifically labeled -otherwise shall fall under the this license (which is BSD 2-clause). - -In all cases, every effort has been made to give credit where credit is due. -You will find these acknowledgments embedded in the source code. You can see -them in "CREDIT:" and/or "@author" lines. -Also see the [Contributors page](https://github.com/rubyworks/facets/wiki/Contributors) -on the Wiki for a list of all contributing Rubyists. If anyone is missing from -the list, please let us know so we can correct. Thanks. - -This collection was put together by, and much of it written by [trans](https://github.com/trans). -If need be, he can be reached via email at transfire at gmail.com. - - -## License - -The collection PER COLLECTION is licensed as follows: - - Ruby Facets - Copyright (c) 2005 Rubyworks - - Distributed under the terms of the BSD-2 License (same as Ruby license). - -The BSD 2 Clause License is a simple open source license. The complete text of the -license accompany this document (see the enclosed LICENSE file). - -Acknowledgments and Copyrights for particular snippets of borrowed code -are given in their respective source. At this point, all licensing has been normalized -for all included code. Original authors have given permission for inclusion of their -code under such license, with appropriate credit citations. +Issues and pull requests are welcome. Start with [CONTRIBUTING.md](CONTRIBUTING.md) for the library's method organization, demos, and test conventions. The test suite runs with: +```sh +bundle install +bundle exec rake test +``` -## "ALL YOUR BASE ARE BELONG TO RUBY!" +[Source](https://github.com/rubyworks/facets) · [Issues](https://github.com/rubyworks/facets/issues) · [Website](https://rubyworks.github.io/facets/) -Ruby Facets, Copyright (c) 2005 Rubyworks +## License and credits -Do you Ruby? (https://ruby-lang.org) +Facets is distributed under the [BSD 2-Clause License](LICENSE.txt). Thomas Sawyer started the project, and many Rubyists have contributed code, ideas, tests, and documentation. Individual files record additional credits where applicable. +*All your base are belong to Ruby.* diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..494f8eb42 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,11 @@ +# Facets website + +The current GitHub Pages site is served directly from `docs/`. Edit the four page fragments and historical post fragments in `_src/`, and the shared stylesheet in `assets/styles/site.css`, then run: + +```sh +ruby docs/build.rb +``` + +Commit the generated HTML pages, including pages under `posts/`, with the source changes. The build uses only Ruby's standard library. `atom.xml` is a small static release feed and is edited directly. + +The `.page`, `.post`, `brite.yml`, and `assets/layouts/` files are retained from the former Brite site for historical reference; they are not inputs to this build. The article copy in `_src/archive/` was taken from the original posts. It describes its original release period and should not be used as current installation or API guidance. diff --git a/docs/_src/archive/2008-01-01-how-facets-was-born.html b/docs/_src/archive/2008-01-01-how-facets-was-born.html new file mode 100644 index 000000000..190d02a34 --- /dev/null +++ b/docs/_src/archive/2008-01-01-how-facets-was-born.html @@ -0,0 +1,16 @@ +

As programmers are wont to do, I started collecting reusable pieces of +Ruby long ago. At first it was just a small function here, a useful +module there. Eventually the collection became sizable and I called it TomsLib. +As time wore on and my library grew, I started to feel it worth a general +release and I had renamed it Raspberry Lib. But sometime shortly thereafter +I hit upon the idea of atomicity of the core extensions. And that's how the +name Facets came about --it's all about the little things. Of course, that name +took a while to decide upon too. The library was almost called "Atomix & Trix"!

+ +

Facets has eveolved considerably over the years --and lessons were learned. Probably +the biggest lesson was the 2.0 release, where the idea of atomicity was eroded and +and alternate means of library requiring was attempted. Both were rectified by 2.4.

+ +

Much has changed since those first days. But time has been good to Facets. +Today, Facets is a more solid and leaner library than ever before and will +continue in the fashion for version to come.

diff --git a/docs/_src/archive/2008-03-24-release-2-4.html b/docs/_src/archive/2008-03-24-release-2-4.html new file mode 100644 index 000000000..ebe212355 --- /dev/null +++ b/docs/_src/archive/2008-03-24-release-2-4.html @@ -0,0 +1,57 @@ +

Facets 2.4.3 is now out in the wild. The release is primarily a maintenance +release —fixing a handful of small bugs and adding some small feature +improvements, but a few significant changes are also present.

+ +
    +
  • Moved Mentalguy's lazy.rb to CORE!
  • +
  • Moved Indexable and Stackable to core.
  • +
  • Added Time#trunc and Time#round to CORE.
  • +
  • Added Ken Bloom's DictionaryMatcher class (maybe renamed in future version)
  • +
  • Added Array#recursively and fixed bug in Hash#recursively.
  • +
  • Added kernel/instance method which provides a fluent interface to private object space.
  • +
  • Renamed Class#to_pathname and #to_methodname to #pathize and #methodize.
  • +
  • Changed File#rewrite to not use the in-place change of the string.
  • +
  • Changed Dictionary#first and #last to take optional arguments.
  • +
  • Deprecated Hash#keys_to_s and Hash#keys_to_sym (use #rekey).
  • +
  • Deprecated Console:: namespace for ANSICode.
  • +
  • Deprecated ruby.rb, which was a sort 1.9 compatibility layer.
  • +
  • The ruby.rb methods were moved to core, wrapped in a 1.9 condition.
  • +
  • Fixed Time#hence changed years when changing months.
  • +
  • Fixed Time#hence to flip year correctly when adding months.
  • +
  • Improved File#rootname, it is now more robust.
  • +
  • Made FileUtils#whereis a module_function again.
  • +
  • Use "lib/lore" to separate extensions to Ruby's standard library.
  • +
+ + +

Note that this release does not include a setup.rb script. We are working +on a new version of this script, which we plan to include in the next +release.

+ +

Special thanks to:

+ +
    +
  • Ken Bloom
  • +
  • Nick Caruso
  • +
  • Evgeniy Dolzhenko
  • +
  • Andy Freeman
  • +
  • Tomasz Muras
  • +
  • Dave Myron
  • +
+ + +

And of course, to anyone else I failed to mention that has contributed.

+ +

Finally, Facets 2.4+ now encourages using:

+ +
require 'facets'
+
+ +

when testing, even if you are cherry-picking methods. It may seem counter-intuitive, +but it actually proves more advantages to do this for the sake of improved +interoperability. The practice of cherry-picking can become problematic if +other dependent libraries have cherry-picked different methods, and the +the different choices go unaccounted and untested.

+ +

Facets is almost fully interoperable with ActiveSupport and Ruby 1.9. We +will continue to improve this interoperability in upcoming releases.

diff --git a/docs/_src/archive/2009-07-21-new-website.html b/docs/_src/archive/2009-07-21-new-website.html new file mode 100644 index 000000000..f0f614f71 --- /dev/null +++ b/docs/_src/archive/2009-07-21-new-website.html @@ -0,0 +1,8 @@ +

The old Ruby Facets website was a static 100% XML/XSLT site. When I originally created +the site, I though XML/XSLT suredly was the pinnicale and proper way to build a +modern site --for no other reason that XSL is a pain in the ass! Well, we all know +the ultimate outcome of this story. XML/XSLT is turning out to be an exmplar of +over engineering by academics.

+ +

The new Facets website runs of Jekyll, a static site generator supoprted by GitHub. +(another good site tool is Shunman)

diff --git a/docs/_src/archive/2009-08-22-release-2-7.html b/docs/_src/archive/2009-08-22-release-2-7.html new file mode 100644 index 000000000..97ca89f07 --- /dev/null +++ b/docs/_src/archive/2009-08-22-release-2-7.html @@ -0,0 +1,122 @@ +

Facets 2.7 is most significant release of Facets since 2.4. Rather then trickle-release +these changes over the course of the 2.6.x series, I made the decision to let 2.7 have them +all at once. In so doing this release nearly completes the process of trimming down +the MORE library to its essentials. Over 40 high-level libraries have been spun-off +as separate gems and/or deprecated. No doubt this is a big change for Facets, and the +transition may be a bit bumpy over the short-term, but I am certain that in the long-run +everyone involved will be better served. To help, I have listed the effected libraries +and the alternate gems available to take their place.

+ +

A few other changes have also been made in the release that may also effect your code. +In particular you should note that #class_extension has been renamed to #class_extend +(require 'facets/class_extend'). In addition we have added a few new core methods such +as Exception#raised? and Symbol#thrown?.

+ +

Spun-Off Projects

+ +

These libraries have been deprecated from Facets entirely, but are available +as separate gems (or soon will be).

+ +
LIBRARY               GEM
+-------------------   -------------------------
+overload.rb           overload
+binreadable.rb        binaryio
+downloader.rb         downloader
+xoxo.rb               xoxo
+bicrypt.rb            bicrypt
+typecast.rb           typecast
+association.rb        association
+syncarray.rb          sync
+synchash.rb           sync
+paramix.rb            paramix
+crypt.rb              crypt3
+lrucache.rb           lrucache
+net/smtp_tls.rb       smtp_tls
+advisable.rb          advisable
+buildable.rb          buildable
+memoizer.rb           memoizer
+harray.rb             sparray
+sparse_array.rb       sparray
+iteration.rb          iteration
+interval.rb           stick
+infinity.rb           stick
+pool.rb               pool
+linkedlist.rb         linkedlist
+semaphore.rb          semaphore
+pqueue.rb             pqueue
+censor.rb             language
+macther.rb            language
+basex.rb              radix
+minitar.rb            archive-tar-minitar, folio
+
+ +

Spun-Off But Still Available

+ +

These libraries have been spun-off into stand-alone gems, but remain +available via Facets too. Ultimately some of these will be removed +from Facets too (in particular the ansi libraries).

+ +
LIBRARY               GEM
+-------------------   -------------------------
+ansicode.rb           ansi
+progressbar.rb        ansi
+logger.rb             ansi
+tracepoint.rb         tracepoint
+dictionary.rb         dictionary
+recorder.rb           recorder
+ostructable.rb        ostructable, openhash
+openobject.rb         openhash
+opencollection.rb     openhash
+opencascade.rb        openhash
+openhash.rb           openhash
+openmodule.rb         openmodule
+fileable.rb           fileable
+expirable.rb          expirable
+enumerablepass.rb     enumargs
+
+ +

Deprecations Without Current Replacement

+ +

The libraries have been deprecated but do not yet have replacements. +Separate gems for these are planned though.

+ +
* bbcode.rb
+* ini.rb
+* settings.rb
+* xmlhash.rb
+
+ +

Deprecations Merged Into CORE

+ +

These libraries have been deprecated because their functionality was merged into +the CORE library and/or made available in some another way.

+ +
* 1stclassmethod.rb   #method! and #instance_method! are now part of CORE.
+* elementor.rb        #per has been added to CORE.
+* elementwise.rb      #ewise has been added to CORE.
+* consoleutils.rb     #ask is in CORE, for the rest see Ansi or Clio project.
+* attr.rb             Added Module#attr_setter to CORE, and separated the rest in MORE.
+
+ +

General Deprecations

+ +

These libraries have simply been deprecated because they were found lacking in +some significant fashion.

+ +
* nilstatus.rb        Poved rather useless, not to mention trivial.
+* heap.rb             Heap was just an alias for PQueue anyway. Use 'pqueue' instead.
+* dependency.rb       Other solutions exist that are much better (like Advisable).
+* classmethods.rb     #class_extend solution is more robust.
+* ziputils.rb         Have a look at Folio (gem install folio) for replacement.
+* unheritable.rb      Implementation is trivial and usefulness questionable.
+* instantise.rb       Replaced by instance_function.rb.
+
+ +

In addition to all this we've also taken some time to ensure Ruby Facets is more compatible +with Ruby 1.9 --indeed, at this point, it should be very close to fully compatibility. In +the process of doing this, btw, it has become clear that Ruby 1.9 picked up a good number +of methods already supported by Facets (some with the same exact names and some with +changed names). There's no way to know if Facets had any influence in these additions +to 1.9, but at the very least we can be sure that Facets contributed to "airing the field" +that led to their addition. That's a great thing, as it means Facets is directly contributing +to Ruby's future. I hope that will continue.

diff --git a/docs/_src/archive/2009-11-09-release-2-8.html b/docs/_src/archive/2009-11-09-release-2-8.html new file mode 100644 index 000000000..64630b604 --- /dev/null +++ b/docs/_src/archive/2009-11-09-release-2-8.html @@ -0,0 +1,62 @@ +

Facets 2.8 effectively completes the MORE library clean-up which peaked +with the previous 2.7 release. In so doing, five additional libraries +have been deprecated:

+ +
    +
  • fileable.rb (too esoteric)
  • +
  • ioredirect.rb (needs better implementation)
  • +
  • coroutine.rb (because of Fiber)
  • +
  • capsule.rb (may be spun-off)
  • +
  • recorder.rb (may be spun-off)
  • +
+ + +

Three other libraries have been deprecated, but have been spun-off +to the new 'ansi' project:

+ +
    +
  • ansicode.rb
  • +
  • progressbar.rb
  • +
  • logger.rb
  • +
+ + +

This version of Facets also reverts a few of the deprecations made before -- +reconsiderations made due to analysis of the code as suitable for release +as separate projects. These libs will thus remain in Facets's MORE library +at least for the forseeable future.

+ +
    +
  • ini.rb
  • +
  • linkedlist.rb
  • +
  • matcher.rb
  • +
  • memoizer.rb
  • +
  • roman.rb
  • +
  • semaphore.rb
  • +
+ + +

Other minor enhancements have also been made in the release. These include:

+ +
    +
  • Kernel#extend can now take a block
  • +
  • Fixed kernel#d so it is useable
  • +
  • Added method #at_rand to Range in random.rb (thanks to Tyler Rick).
  • +
  • Added method #map_detect to Enumerable (thanks to Scott Taylor).
  • +
  • Added method #/ to String, which calls File.join.
  • +
  • Added method #newlines and #cleanlines to String.
  • +
  • String#titlecase now handles apostrophes.
  • +
  • BasicObject/BlankSlate is more compliant with 1.9.1's design.
  • +
  • Enumerable#count can take multiple items, treats them as a logical Or.
  • +
  • Class#class_extend extends class level, rather than use class_eval.
  • +
  • Integer#succ(n) becomes Fixnum#succ(n) in succ.rb.
  • +
  • inheritor.rb has been rewritten.
  • +
  • The Shellwords extensions have been reworked.
  • +
  • Added #similarity method to String.
  • +
  • Added a Levenshtein edit_distance method to String.
  • +
+ + +

In addition to all this, we have recently set up a new Ruby 1.9 compliance procedure +using RunCodeRun.com. Actually RunCodeRun helps us to ensure 1.8.6 compabiltiy as well. +This is great tool for improving code quality, and comes highly recommended.

diff --git a/docs/_src/archive/2010-09-01-release-2-9.html b/docs/_src/archive/2010-09-01-release-2-9.html new file mode 100644 index 000000000..37e0c8a2e --- /dev/null +++ b/docs/_src/archive/2010-09-01-release-2-9.html @@ -0,0 +1,28 @@ +

Facets 2.9 is fairly extensive as it was originally intended to be v3.0. +After further consideration it was decided to reserve v3.0 for something a +little bolder (to be announced). The primary goal of this release was to +trim Facets down to a true core extensions library. All tertiary add-on classes +and mixins have now been spun-off to other projects. Only a very select set of +general purposes classes and mixins remain.

+ +

A new TOUR library division has been added to complement CORE and MORE. +This division houses purely optional extensions. The new division serves +a couple of useful purposes. In particular, it helps separates the standard +library extensions from optional core extension in the RDocs and thus makes +the perfect place to vet new extension ideas.

+ +

One important change that will effect anyone using Facets along side +ActiveSupport is that Facets no longer tries to conditionally avoid +method overlaps with ActiveSupport. This is fine for the upcoming +ActiveSupport 3.0 library which extends core classes directly instead of +using mixins. One need only require 'facets' in Rails' config/preinitializer.rb +file, and ActiveSupport will take precedence over Facets. For older versions +of ActiveSupport, the best approach is to cherry pick from Facets just the +extensions you want, thus avoiding any conflicts. There are actually only a +dozen or so overlaps and all are intended to compatible, but it doesn't hurt +to be sure.

+ +

I won't detail each change here, have a look at the HISTORY.rdoc file for that. +Needless to say, it's a good idea to read it over to see what changes might +effect your usage --and it also gives you a glimpse at what other extensions are +available that you might not yet be familiar.

diff --git a/docs/_src/index.erb b/docs/_src/index.erb new file mode 100644 index 000000000..b2741f948 --- /dev/null +++ b/docs/_src/index.erb @@ -0,0 +1,55 @@ +
+
+
+

A Ruby library since 2005

+

More of Ruby,
one method
at a time.

+

A thoughtfully collected set of extensions for Ruby's core classes and standard library. Load the whole core collection or pick just the methods you need.

+ +

Version 3.2.2 Ruby 3.1+ BSD 2-Clause

+
+
+
+
+
find your facetRuby
+
# Load only what you need
+require 'facets/array/to_ranges'
+
+[1, 2, 3, 6, 7].to_ranges
+#=> [1..3, 6..7]
+
+ +
+
+
+ +
01 Small, focused files02 Core + standard libraries03 Your Ruby, your choices
+ +
+
+

THE IDEA

Good ideas deserve
a shared home.

Facets brings useful Ruby methods together in a form you can discover, reuse, and improve. Each extension stays easy to find and easy to require.

+
+

01 / GRANULAR

One file, one idea

Most methods have their own file. Add a single method without loading a larger set of extensions.

+

02 / FAMILIAR

Ruby, extended

Build on the classes and modules you already use, from Array and String to parts of the standard library.

+

03 / COMMUNITY

Made together

Years of contributions and refinement live in one collection, with tests and source credits alongside the code.

+
+
+
+ +
+
+

MAKE IT YOURS

Start small.
Go further.

Choose the amount of Facets that fits your project. You can change that choice as your needs grow.

See the loading guide
+
+
01

A single method

require 'facets/time/stamp'
+
02

A core class

require 'facets/time'
+
03

The core collection

require 'facets'
+
04

A standard library extension

require 'facets/ostruct'
+
+
+
+ +
+

LATEST RELEASE

Fresh facets
for modern Ruby.

Version 3.2.2 includes compatibility fixes across Ruby 3.1–3.4, following the 3.2 modernization release.

Read the release notes
RUBY FACETS3.2.2JUNE 2026
+
diff --git a/docs/_src/layout.erb b/docs/_src/layout.erb new file mode 100644 index 000000000..3daa672d5 --- /dev/null +++ b/docs/_src/layout.erb @@ -0,0 +1,45 @@ + + + + + + + + <%= title %> + + + + + + + + +
<%= content %>
+ + + + diff --git a/docs/_src/learn.erb b/docs/_src/learn.erb new file mode 100644 index 000000000..c80de5732 --- /dev/null +++ b/docs/_src/learn.erb @@ -0,0 +1,24 @@ +

THE GUIDE

Find your way
into Facets.

Install the gem, choose how much to load, and make Ruby feel a little more like yours.

+
+

01 / GET READY

Install Facets

Facets 3.2.2 requires Ruby 3.1 or newer. Install it directly with RubyGems or add it to a Bundler project.

TERMINAL
gem install facets
GEMFILE
gem 'facets', require: false

require: false keeps Bundler from loading the entire core collection automatically, so you can choose the files your project needs.

+

02 / CHOOSE YOUR SCOPE

Load what fits

Most core extension methods are stored in individual files. You can require one method, a class's core methods, or the core collection.

RUBY
# One method
+require 'facets/array/to_ranges'
+
+# A class's core extensions
+require 'facets/string'
+
+# Most core extensions
+require 'facets'

Standard library extensions are separate from the core collection. Require each one explicitly. For example, require 'facets/ostruct' loads Ruby's ostruct and the Facets additions for it.

Using Ruby 3.5+? Add the ostruct gem separately if you use Facets' OpenStruct extensions. Ruby no longer includes it as a default gem.
+

03 / SEE IT WORK

A few useful facets

These examples use methods present in the 3.2 release.

RUBY
require 'facets/array/to_ranges'
+[1, 2, 3, 6, 7].to_ranges
+#=> [1..3, 6..7]
+
+require 'facets/string/dashcase'
+'Ruby Facets'.dashcase
+#=> "ruby-facets"
+
+require 'facets/range/intersection'
+Range.intersection(1..10, 5..15)
+#=> 5..10

Extensions add methods to Ruby's existing classes. When combining libraries that extend the same classes, choose your requires deliberately and check for method name overlap.

+

04 / KEEP EXPLORING

Find the right method

RubyDoc.info hosts generated API documentation; check the displayed gem version when browsing. In the published 3.2.2 gem, lib/core belongs to the core collection and lib/standard contains separately loaded libraries. The source repository also contains unreleased changes, including a new lib/rails area.

+
diff --git a/docs/_src/news.erb b/docs/_src/news.erb new file mode 100644 index 000000000..730f74e97 --- /dev/null +++ b/docs/_src/news.erb @@ -0,0 +1,7 @@ +

RELEASES & HISTORY

A living Ruby
collection.

Facets has been growing since 2005. Here are the recent releases and a path back through its story.

+

LATEST RELEASES

Facets 3.2

The 3.2 series brings the library forward for Ruby 3.1 and newer. Work merged since 3.2.2 is listed under Unreleased in the release history.

+
3.2.215 JUN 2026

LATEST

Compatibility, polished

Fixes range intersection on Ruby 3.1 and 3.2, restores Range#overlap? where Ruby does not provide it, and corrects Binding#caller_locations argument handling.

Read changes
+
3.2.114 JUN 2026

Core loading restored

Repairs stale require paths that affected require 'facets' in 3.2.0, and adds a load-path regression check. Also adds OpenDSL and PIC.

Read changes
+
3.2.0APR 2026

Modern Ruby foundation

Moves the minimum Ruby version to 3.1, adds methods such as Array#to_ranges and String#dashcase, and retires extensions now built into Ruby.

Read migration notes
+
+

FROM THE ARCHIVE

Twenty years
of ideas.

These posts are preserved as published. Their install advice and API links describe older Facets releases; use the current guide for 3.x.

diff --git a/docs/_src/source.erb b/docs/_src/source.erb new file mode 100644 index 000000000..73c9a756b --- /dev/null +++ b/docs/_src/source.erb @@ -0,0 +1,7 @@ +

OPEN SOURCE

Shape the next
facet.

Facets was made by Rubyists sharing useful ideas. There is room for better methods, better tests, clearer docs, and thoughtful bug reports.

+
+

DEVELOP LOCALLY

From idea
to test.

Core extensions live under lib/core/facets, standard library extensions under lib/standard/facets, and unreleased Rails-compatible helpers under lib/rails/facets. Keep focused changes close to their tests and demos.

Contribution conventions
TERMINAL
git clone https://github.com/rubyworks/facets.git
+cd facets
+bundle install
+bundle exec rake test
+

PEOPLE & LICENSE

Built together.

Thomas Sawyer began Facets in 2005. Many contributors have shaped its methods, tests, and documentation since then. Credits for individual pieces appear in the source, and the collection is distributed under the BSD 2-Clause License.

Read the license
diff --git a/docs/assets/images/cherries.svg b/docs/assets/images/cherries.svg new file mode 100644 index 000000000..b2d2cd1a8 --- /dev/null +++ b/docs/assets/images/cherries.svg @@ -0,0 +1,8 @@ + + Two cherries + + + + + + diff --git a/docs/assets/styles/site.css b/docs/assets/styles/site.css index 64a817418..54b4d9e9e 100644 --- a/docs/assets/styles/site.css +++ b/docs/assets/styles/site.css @@ -1,324 +1,243 @@ -/* - * FACETS STYLESHEET - * Thomas Sawyer, 2007 - * - */ - - -/* GENERAL */ - -* { - margin : 0; - padding : 0; - border : none; -} - -body { - margin : 0; - padding : 0; - color : black; - background : white; - text-align : center; /* for IE */ - /*background : url(../media/RubyFacetsShadow2.png) bottom no-repeat white;*/ - font-size : 12px; -} - -p { - font-size : 1em; - color : #222222; - text-align : justify; - margin : 10px 10px 15px 0px; - line-height : 1.5em; -} - -a { - font-weight : bold; - text-decoration : none; - color : #660066; -} - -pre { - background : white; - font-size : 0.8em; - padding : 5px 0 10px 20px; - color : #333; -} - -blockquote { - margin : 5px 0px 0px 5px; - font-style : italic; - font-weight : bold; - font-size : 0.8em; - color : #999; -} - -p a { - font-weight : normal; -} - -td { - vertical-align: top; -} - -ul { margin-left: 30px; margin-bottom: 30px; } -li { color: black; font-family: monospace; font-size: 0.9em; } - -h3 { font-weight: normal; } - -td { padding: 5px; } - -#container { - text-align: center; - padding-bottom: 30px; +:root { + color-scheme: light; + --ink: #241b24; + --muted: #665e67; + --plum: #201523; + --plum-soft: #312038; + --ruby: #e24d51; + --ruby-dark: #b72f43; + --paper: #fbf9f5; + --cream: #f3eee6; + --line: #e4ddd6; + --serif: Georgia, 'Times New Roman', serif; + --sans: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; +} +* { box-sizing: border-box; } +html { scroll-behavior: smooth; } +body { margin: 0; background: var(--paper); color: var(--ink); font-family: var(--sans); font-size: 16px; line-height: 1.6; } +a { color: inherit; } +a:hover { color: var(--ruby-dark); } +a:focus-visible { outline: 3px solid var(--ruby); outline-offset: 4px; border-radius: 2px; } +button, code, pre { font: inherit; } +code, pre { font-family: var(--mono); } +code { font-size: .88em; } +pre { margin: 0; overflow-x: auto; } +h1, h2, h3, p { margin-top: 0; } +h1, h2, h3 { line-height: 1.1; } +h1, h2 { letter-spacing: -.045em; } +h2 { font-family: var(--serif); font-size: clamp(2.6rem, 5vw, 4.6rem); font-weight: 400; } +h2 em, h1 em { color: var(--ruby); font-weight: 400; } +p { margin-bottom: 1.25em; } +.shell { width: min(100% - 64px, 1160px); margin-inline: auto; } +.skip-link { position: absolute; z-index: 20; top: -80px; left: 16px; padding: 8px 14px; background: white; color: var(--ink); } +.skip-link:focus { top: 12px; } + +.site-header { position: relative; z-index: 4; background: var(--plum); color: #f9f3ec; border-bottom: 1px solid #4b394c; } +.header-inner { min-height: 88px; display: flex; align-items: center; gap: 28px; } +.brand { display: inline-flex; align-items: center; gap: 11px; color: inherit; text-decoration: none; white-space: nowrap; font-size: 1.15rem; letter-spacing: -.035em; } +.brand:hover { color: #fff; } +.brand strong { font-weight: 760; } +.brand-mark { display: block; width: 39px; height: 39px; object-fit: contain; } +.site-nav { display: flex; align-items: center; gap: clamp(14px, 2vw, 32px); margin-left: auto; } +.site-nav a { padding: 10px 1px; color: #d1c5cf; text-decoration: none; font-size: .88rem; font-weight: 620; } +.site-nav a:hover, .site-nav a[aria-current="page"] { color: #fff; } +.site-nav a[aria-current="page"] { box-shadow: 0 2px 0 var(--ruby); } +.header-github { margin-left: 12px; color: #fff; border: 1px solid #786473; padding: 9px 14px; text-decoration: none; font-size: .85rem; font-weight: 700; white-space: nowrap; } +.header-github:hover { background: #413044; color: white; } +.header-github span { margin-left: 12px; color: #ff9ca0; } + +.hero { position: relative; overflow: hidden; background: radial-gradient(circle at 85% 12%, #4c3045 0, transparent 33%), var(--plum); color: #fbf7f1; } +.hero-grid { display: grid; grid-template-columns: 1.06fr .94fr; align-items: center; min-height: 630px; gap: 56px; padding-block: 60px 80px; } +.eyebrow, .kicker { font-size: .73rem; font-weight: 800; letter-spacing: .19em; text-transform: uppercase; } +.eyebrow { display: flex; align-items: center; gap: 13px; color: #f3a1a0; margin-bottom: 29px; } +.eyebrow-line { display: inline-block; width: 25px; height: 1px; background: currentColor; } +.hero h1, .page-hero h1 { font-family: var(--serif); font-size: clamp(3.8rem, 6vw, 6.35rem); font-weight: 400; margin: 0 0 27px; line-height: .99; } +.hero-lede { max-width: 560px; font-size: 1.12rem; color: #d7cbd2; line-height: 1.75; } +.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; } +.button { display: inline-flex; align-items: center; justify-content: center; gap: 24px; min-height: 48px; padding: 11px 18px; text-decoration: none; font-size: .88rem; font-weight: 750; transition: transform .18s, background .18s; } +.button:hover { transform: translateY(-2px); } +.button-primary { background: var(--ruby); color: #fff; } +.button-primary:hover { background: #f05d63; color: #fff; } +.button-outline { border: 1px solid #766372; color: #fff; } +.button-outline:hover { background: #3c2a40; color: #fff; } +.button-light { background: #fff8ef; color: var(--plum); } +.button-light:hover { background: #fff; color: var(--plum); } +.hero-note { margin: 30px 0 0; color: #a99aa9; font-size: .75rem; letter-spacing: .04em; text-transform: uppercase; } +.hero-note strong { color: #f8efed; } +.hero-note span { margin: 0 7px; color: var(--ruby); } +.hero-visual { min-height: 420px; display: grid; place-items: center; position: relative; isolation: isolate; } +.orbit { position: absolute; border: 1px solid #6e4c5d; border-radius: 50%; aspect-ratio: 1; z-index: -1; } +.orbit-one { width: min(470px, 100%); transform: rotate(-25deg) scaleY(.72); } +.orbit-two { width: min(540px, 113%); transform: rotate(23deg) scaleY(.78); border-color: #4b3545; } +.code-window { width: min(100%, 490px); background: #1a1520; border: 1px solid #806578; box-shadow: 0 28px 85px rgba(0,0,0,.34); transform: rotate(2deg); } +.code-title { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 12px 18px; color: #c8b9c6; font-size: .71rem; letter-spacing: .08em; border-bottom: 1px solid #42313e; text-transform: uppercase; } +.window-dots { display: flex; gap: 5px; } +.window-dots i { width: 7px; height: 7px; border-radius: 50%; background: #b87980; } +.window-dots i:nth-child(2) { background: #bc9e7d; } +.window-dots i:nth-child(3) { background: #7a9b8f; } +.code-language { color: #8b7988; } +.code-window pre { padding: 28px 24px 33px; color: #f6ede8; font-size: clamp(.78rem, 1.1vw, .9rem); line-height: 1.9; } +.code-comment { color: #9d8e9e; } +.code-keyword, .code-method { color: #f58d96; } +.code-string { color: #efc096; } +.code-number { color: #d2bbec; } +.hero-cherries { position: absolute; right: -8px; bottom: 0; width: 106px; height: 106px; filter: drop-shadow(0 12px 15px #160c14); transform: rotate(-15deg); } + +.facts-band { background: #bd3949; color: #fff3f0; } +.facts-inner { display: flex; justify-content: space-between; align-items: center; min-height: 70px; gap: 20px; font-size: .76rem; font-weight: 750; letter-spacing: .12em; text-transform: uppercase; } +.facts-inner b { font-family: var(--serif); font-size: 1.2rem; font-weight: 400; margin-right: 12px; opacity: .65; letter-spacing: 0; } +.section { padding-block: clamp(72px, 9vw, 120px); } +.section-light { background: var(--paper); } +.section-cream { background: var(--cream); } +.section-heading { display: grid; grid-template-columns: .8fr 1.65fr 1fr; gap: 28px; align-items: start; margin-bottom: 48px; } +.section-heading h2 { margin-bottom: 0; } +.section-heading > p:last-child { padding-top: 8px; color: var(--muted); font-size: 1rem; } +.section-heading-idea { display: block; max-width: 780px; } +.section-heading-idea h2 { margin-bottom: 20px; } +.section-heading-idea > p:last-child { padding-top: 0; max-width: 620px; } +.section-heading.narrow { display: block; max-width: 760px; } +.section-heading.narrow h2 { margin-bottom: 24px; } +.section-heading.narrow > p:last-child { max-width: 680px; } +.kicker { color: var(--ruby-dark); margin: 10px 0 22px; } +.kicker-light { color: #f5abb0; } +.feature-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; } +.feature-card { background: #fff; border: 1px solid var(--line); padding: 30px; min-height: 280px; } +.feature-icon { display: inline-flex; align-items: center; justify-content: center; color: var(--ruby-dark); font-size: 2.1rem; width: 56px; height: 56px; border: 1px solid #ead8d8; margin-bottom: 28px; } +.feature-icon-circle::before { content: ''; width: 22px; height: 22px; border: 2px solid currentColor; border-radius: 50%; } +.feature-number { margin-bottom: 10px; color: #a04755; font-size: .68rem; font-weight: 800; letter-spacing: .15em; } +.feature-card h3 { font-family: var(--serif); font-weight: 400; font-size: 1.6rem; margin-bottom: 14px; } +.feature-card p:last-child { color: var(--muted); font-size: .91rem; margin-bottom: 0; } +.split-section { display: grid; grid-template-columns: .9fr 1.1fr; gap: clamp(44px, 8vw, 110px); align-items: start; } +.split-section h2 { margin-bottom: 24px; } +.section-intro { max-width: 420px; color: var(--muted); } +.text-link { display: inline-flex; align-items: center; gap: 22px; color: var(--ruby-dark); text-decoration: none; font-weight: 800; font-size: .87rem; border-bottom: 1px solid var(--ruby-dark); padding-bottom: 6px; } +.text-link:hover { color: #761827; } +.load-list { border-top: 1px solid #cfc5be; } +.load-row { display: grid; grid-template-columns: 42px 1fr; gap: 15px; padding: 22px 0; border-bottom: 1px solid #cfc5be; } +.load-index { padding-top: 2px; font-family: var(--serif); color: #b24351; font-size: 1.3rem; } +.load-row h3 { font-size: .88rem; margin-bottom: 8px; } +.load-row code { display: inline-block; padding: 6px 10px; color: #512537; background: #e9e0da; font-size: .82rem; } +.release-section, .source-credit { background: #352035; color: #fff8f1; } +.release-grid { display: grid; grid-template-columns: 1fr .8fr; align-items: center; gap: 80px; } +.release-grid h2 { margin-bottom: 24px; } +.release-grid p:not(.kicker) { color: #d8c6d2; max-width: 500px; } +.release-grid .button { margin-top: 12px; } +.release-stamp { width: min(100%, 350px); aspect-ratio: 1; border: 1px solid #946d80; border-radius: 50%; display: flex; flex-direction: column; align-items: center; justify-content: center; justify-self: center; transform: rotate(-12deg); color: #f7b6b7; letter-spacing: .16em; font-size: .72rem; } +.release-stamp::before { content: ''; display: block; width: 42px; height: 42px; background: url('../images/cherries.svg') center / contain no-repeat; } +.release-stamp strong { color: white; font-family: var(--serif); font-size: clamp(4rem, 7vw, 6rem); font-weight: 400; letter-spacing: -.06em; line-height: 1.25; } +.release-stamp-small { margin-top: 8px; } + +.page-hero { background: radial-gradient(circle at 75% 25%, #483045, transparent 28%), var(--plum); color: #fff8ef; padding-block: clamp(72px, 10vw, 120px); } +.page-hero h1 { margin-bottom: 28px; } +.page-hero > .shell > p:last-child { color: #d4c4d0; max-width: 620px; font-size: 1.1rem; line-height: 1.75; margin-bottom: 0; } +.guide-grid { display: grid; grid-template-columns: 220px 1fr; gap: clamp(40px, 7vw, 100px); } +.guide-aside { position: sticky; top: 24px; align-self: start; display: grid; gap: 8px; } +.guide-aside .kicker { margin-bottom: 11px; } +.guide-aside a { color: #5f555d; text-decoration: none; font-size: .88rem; padding: 6px 0; } +.guide-aside a:hover { color: var(--ruby-dark); } +.guide-content { max-width: 760px; } +.guide-block { scroll-margin-top: 30px; padding: 0 0 70px; margin-bottom: 65px; border-bottom: 1px solid var(--line); } +.guide-block:last-child { margin-bottom: 0; padding-bottom: 0; border-bottom: 0; } +.guide-block h2 { font-size: clamp(2.4rem, 4vw, 3.75rem); margin-bottom: 22px; } +.guide-block > p:not(.kicker) { max-width: 690px; color: var(--muted); } +.guide-block a { color: var(--ruby-dark); } +.snippet { margin: 24px 0; background: #241923; color: #f9f2ed; border: 1px solid #493447; } +.snippet-label { color: #d8a2a9; padding: 11px 18px; border-bottom: 1px solid #493447; font-size: .68rem; font-weight: 800; letter-spacing: .17em; } +.snippet pre { padding: 20px 22px; font-size: .86rem; line-height: 1.85; } +.callout { border-left: 3px solid var(--ruby); background: #f5ebe6; padding: 18px 22px; color: #53424d; font-size: .91rem; } +.callout strong { color: #943449; } +.resource-list { margin-top: 30px; border-top: 1px solid var(--line); } +.resource-list a { display: flex; align-items: center; justify-content: space-between; padding: 17px 5px; border-bottom: 1px solid var(--line); text-decoration: none; color: var(--ink); font-weight: 750; } +.resource-list a:hover { color: var(--ruby-dark); } +.resource-list small { display: block; color: #766b73; font-size: .76rem; font-weight: 400; } +.timeline { border-top: 1px solid var(--line); } +.timeline-item { display: grid; grid-template-columns: 210px 1fr; gap: 45px; padding: 38px 0; border-bottom: 1px solid var(--line); } +.timeline-date strong { display: block; font-family: var(--serif); font-size: 2.3rem; font-weight: 400; line-height: 1.1; } +.timeline-date span { font-size: .7rem; color: var(--ruby-dark); font-weight: 800; letter-spacing: .14em; } +.timeline-item h3 { font-family: var(--serif); font-size: 1.75rem; font-weight: 400; margin-bottom: 11px; } +.timeline-item p { max-width: 720px; color: var(--muted); } +.timeline-item .tag { display: inline-block; background: #f9e8e7; color: #a33847; padding: 3px 8px; margin-bottom: 16px; font-size: .62rem; font-weight: 800; letter-spacing: .13em; } +.timeline-item .text-link { margin-top: 4px; } +.archive-grid { display: grid; grid-template-columns: .8fr 1.2fr; gap: 80px; } +.archive-grid h2 { margin-bottom: 22px; } +.archive-grid p:not(.kicker) { color: var(--muted); } +.archive-list { border-top: 1px solid #cfc5be; } +.archive-list a { display: grid; grid-template-columns: 70px 1fr 20px; gap: 12px; align-items: center; padding: 16px 0; border-bottom: 1px solid #cfc5be; text-decoration: none; font-family: var(--serif); font-size: 1.22rem; } +.archive-list a:hover { color: var(--ruby-dark); } +.archive-list span { color: #a04b56; font-family: var(--sans); font-size: .7rem; font-weight: 800; } +.archive-list b { font-family: var(--sans); font-size: .9rem; font-weight: 400; } +.action-card { display: block; position: relative; text-decoration: none; color: var(--ink); padding-bottom: 58px; } +.action-card:hover { border-color: #cb9ca4; color: var(--ink); transform: translateY(-2px); } +.action-card p { color: var(--muted); font-size: .91rem; } +.card-arrow { position: absolute; left: 30px; bottom: 26px; color: var(--ruby-dark); } +.dev-snippet { margin: 0; align-self: center; width: 100%; } +.credit-grid { display: grid; grid-template-columns: .55fr 1fr; gap: 100px; } +.credit-grid h2 { margin-bottom: 18px; } +.credit-grid p:not(.kicker) { color: #ddcfd9; max-width: 690px; } +.credit-grid .button { margin-top: 8px; } +.archive-hero { padding-block: clamp(60px, 8vw, 100px); } +.archive-hero h1 { font-size: clamp(3rem, 5.4vw, 5rem); max-width: 850px; } +.archive-hero a { color: #ffbcc0; } +.archive-article { max-width: 830px; padding-block: clamp(60px, 8vw, 96px); font-size: 1.05rem; line-height: 1.8; } +.archive-article h2 { font-size: clamp(2rem, 4vw, 3rem); margin: 50px 0 18px; } +.archive-article h3 { font-family: var(--serif); font-size: 1.5rem; margin: 36px 0 14px; } +.archive-article p, .archive-article li { color: #493f48; } +.archive-article ul { padding-left: 1.4em; } +.archive-article a { color: var(--ruby-dark); } +.archive-article code, .archive-article pre { background: #eee8e4; } +.archive-article pre { padding: 18px; margin: 24px 0; } +.archive-back { max-width: 830px; padding-bottom: 80px; } +.site-footer { background: #1a111d; color: #f5edf0; padding-block: 56px; } +.footer-inner { display: flex; justify-content: space-between; gap: 40px; } +.site-footer .brand { margin-bottom: 16px; } +.site-footer p { color: #b8aab5; font-size: .78rem; margin-bottom: 0; } +.footer-links { display: grid; grid-template-columns: repeat(2, auto); align-content: start; gap: 10px 35px; } +.footer-links a { color: #d2c4cf; font-size: .8rem; text-decoration: none; } +.footer-links a:hover { color: #fff; } + +@media (max-width: 900px) { + .hero-grid { grid-template-columns: 1fr; gap: 10px; } + .hero-visual { min-height: 350px; } + .hero h1 { font-size: clamp(4rem, 9vw, 6rem); } + .section-heading { grid-template-columns: 1fr 2fr; } + .section-heading > p:last-child { grid-column: 2; } + .feature-grid { grid-template-columns: repeat(2, 1fr); } + .feature-grid > :last-child { grid-column: span 2; } + .archive-grid { gap: 45px; } +} +@media (max-width: 680px) { + .shell { width: min(100% - 36px, 1160px); } + .header-inner { min-height: 0; flex-wrap: wrap; justify-content: space-between; gap: 0; padding-block: 16px 8px; } + .site-nav { order: 3; width: 100%; margin: 12px 0 0; justify-content: space-between; gap: 8px; border-top: 1px solid #4b394c; } + .site-nav a { font-size: .77rem; padding: 12px 0; } + .header-github { margin: 0; font-size: .75rem; padding: 6px 9px; } + .header-github span { margin-left: 5px; } + .hero-grid { padding-block: 60px 58px; } + .hero h1, .page-hero h1 { font-size: clamp(3.3rem, 12vw, 5rem); } + .hero-lede, .page-hero > .shell > p:last-child { font-size: 1rem; } + .hero-visual { min-height: 295px; } + .code-window { transform: rotate(1deg); } + .hero-cherries { width: 80px; height: 80px; right: -8px; bottom: -10px; } + .facts-inner { justify-content: flex-start; flex-wrap: wrap; gap: 6px 20px; padding-block: 14px; font-size: .65rem; } + .facts-inner b { margin-right: 4px; } + .section-heading, .split-section, .release-grid, .archive-grid, .credit-grid, .guide-grid { display: block; } + .section-heading > p:last-child { max-width: 540px; } + .feature-grid { grid-template-columns: 1fr; } + .feature-grid > :last-child { grid-column: auto; } + .feature-card { min-height: 0; } + .split-section > :first-child, .archive-grid > :first-child { margin-bottom: 36px; } + .release-stamp { width: 260px; margin-top: 45px; } + .guide-aside { position: static; display: flex; flex-wrap: wrap; gap: 4px 14px; margin-bottom: 44px; padding-bottom: 16px; border-bottom: 1px solid var(--line); } + .guide-aside .kicker { width: 100%; margin-bottom: 2px; } + .timeline-item { grid-template-columns: 1fr; gap: 18px; } + .timeline-date strong { display: inline; margin-right: 14px; } + .archive-grid { gap: 30px; } + .credit-grid .kicker { margin-bottom: 25px; } + .footer-inner { display: block; } + .footer-links { margin-top: 28px; } +} +@media (prefers-reduced-motion: reduce) { + html { scroll-behavior: auto; } + .button { transition: none; } } - -/* HEADER */ - -#header { - width : 100%; - height : 120px; - color : white; - text-align : center; - font-weight : bold; - font-size : 4em; - letter-spacing : -1px; - /* background : url(../media/fade_red_up.png) bottom repeat-x white; */ - /* border-bottom : 1px solid #553333; */ -} - -#logo { z-index: 2; width: 480px; } - -/* MENU BAR */ - -#menu { - color : gray; - padding : 10px 0 5px 0; - font-size : 12px; - z-index : 0; - text-align : center; - /*border-bottom : 2px solid #553333;*/ - /*border-top : 2px solid #773333;*/ -} - -#menu a { - font-weight : normal; - font-size : 12px; - font-family : sans-serif, monospace; - color : #660066; - text-decoration : none; -} - -#menu a:hover { - text-decoration : underline; -} - -/* -#drop_shadow { - height : 32px; - background : url(../media/RubyFacetsShadow.png) top repeat-x white; - margin-bottom : -22px; -} -*/ - -/* Content */ - -#content { - text-align : left; /* counter the body center */ - padding : 0; - background : url(../media/RubyFacetsShadowFade.png) top center repeat-x; - /* background : white; */ -} - -.page { - width : 480px; - margin : 0 auto; - padding : 10px 0; - text-align : left; /* counter the body center */ -} - -.sell { - margin : 15px auto; - text-align : center; - padding : 10px 10px 10px 10px; - font-size : 1.5em; - font-family : sans-serif, serif; - color : #222222; - -moz-border-radius-topleft : 1em; border-topleft-radius : 1em; - -moz-border-radius-topright : 1em; border-topright-radius : 1em; - -moz-border-radius-bottomleft : 1em; border-bottomleft-radius : 1em; - -moz-border-radius-bottomright : 1em; border-bottomright-radius : 1em; -} - -.ico img { - -moz-border-radius: 5px; - border-radius : 5px; - width: 72px; - background: white; - text-align: center; - margin-top: 15px; -} - -.sm{ - font-size : 1em; - font-family : sans-serif, serif; - color : #222222; -} - -#copyright { - color: #444444; - text-align: center; - font-size: 0.6em; - padding: 30px 0; - font-family : sans-serif; - font-weight : normal; - width : 480px; - margin : 0 auto; -} - -#doctable td { - text-align : center; - border : 2px solid #cccccc; - padding-right : 10px; - background : white; - -moz-border-radius : 1em; - border-radius : 1em; -} - -/* CLASSES */ - -.r { color: pink; } -.g { color: yellow; } -.b { color: skyblue; } - -.red { color: #ff0044; } - - -.spotlight { - padding-bottom : 10px; - padding-top : 5px; - margin : 5px; - /* - background: #FFFFEE; - border: 1px solid gray; - -moz-border-radius-topleft: 1em; border-topleft-radius: 1em; - -moz-border-radius-topright: 1em; border-topright-radius: 1em; - -moz-border-radius-bottomleft: 1em; border-bottomleft-radius: 1em; - -moz-border-radius-bottomright: 1em; border-bottomright-radius: 1em; - */ -} - -.blurb { - text-align : center; - padding : 5px 0 10px 0; - color : #333333; - font-size : 2.7em; - font-weight : bold; - background : url(../media/fade_yellow_up.jpg) bottom repeat-x; - border-top : 1px solid #999; - border-bottom : 1px solid #999; -} - -.desc { - font-size : .4em; - padding : 15px 15px 20px 15px; - width : 480px; - margin : 0 auto; - /* - background : white; - border : 1px solid #cccccc; - -moz-border-radius :10px; - -webkit-border-radius :10px; - */ -} - -.desc h1 { - margin: 0 0 15px 0; - color: #FF0077; - color: #770077; -} - -.desc .small { - padding-top: 20px; - font-size: 0.7em; - font-family: sans-serif; -} - -div.section { - margin: 10px; - padding-bottom: 10px; -} - -div.page h1 { - margin: 40px 0 15px 0; - color: #442244; -} - -/* -.spotlights a { - color: #4444AA; - text-decoration: none; - font: normal 1.5em monospace; -} - -.spotlights a:hover { - text-decoration: underline; -} - -.spy { - padding-top : 20px; - padding-bottom : 10px; - font-size : 2em; - font-weight : bold; - color : #222222; - text-align : left; -} - -spy img { width: 30px; } -*/ - -.spot { font-weight: bold; color: #FF0077; text-align: left; } - -.emblem { - margin : 0 auto; - border : 1px solid black; - margin-top : 20px; - background : gray; - font-size : 0.9em; - width : 125px; - height : 20px; - line-height : 20px; -} - -.heading { - font: 48pt helvetica; color: #dd00aa; - width: 620px; - margin: 0 auto; - margin-bottom: 0px; - text-align: center; -} - -.item { - margin-bottom: 10px; -} - - -/* MISCELLANEOUS */ - -#apidocs td a { - text-decoration: none; - padding-right: 5px; - -} - -#forkme { - position: absolute; - right: 0; - top: 0; -} - -#forkme img { - margin: 0; - padding: 0; -} - - diff --git a/docs/atom.xml b/docs/atom.xml index 92334582d..c5f3a7a8d 100644 --- a/docs/atom.xml +++ b/docs/atom.xml @@ -1,60 +1,30 @@ - - blog.crantastic.org - - - {{ site.time | date_to_xmlschema }} - http://rubyworks.github.com/facets - - - - {{ post.title | xml_escape }} - - 2010-09-01 - {{ site.url }}{{ post.id }} - - - - - {{ post.title | xml_escape }} - - 2009-11-09 - {{ site.url }}{{ post.id }} - - - - - {{ post.title | xml_escape }} - - 2009-08-22 - {{ site.url }}{{ post.id }} - - - - - {{ post.title | xml_escape }} - - 2009-07-01 - {{ site.url }}{{ post.id }} - - - - - {{ post.title | xml_escape }} - - 2008-03-24 - {{ site.url }}{{ post.id }} - - - - - {{ post.title | xml_escape }} - - 2008-01-01 - {{ site.url }}{{ post.id }} - - - - - \ No newline at end of file + Ruby Facets releases + https://rubyworks.github.io/facets/ + + + 2026-06-15T00:00:00Z + Ruby Facets + + Ruby Facets 3.2.2 + https://rubyworks.github.io/facets/news.html#facets-3-2-2 + + 2026-06-15T00:00:00Z + Compatibility fixes for Range and Binding across Ruby 3.1–3.4. + + + Ruby Facets 3.2.1 + https://rubyworks.github.io/facets/news.html#facets-3-2-1 + + 2026-06-14T00:00:00Z + Restores core collection loading and adds OpenDSL and PIC. + + + Ruby Facets 3.2.0 + https://rubyworks.github.io/facets/news.html#facets-3-2-0 + + 2026-04-01T00:00:00Z + Modernization release for Ruby 3.1 and newer. + + diff --git a/docs/build.rb b/docs/build.rb new file mode 100644 index 000000000..d405ce690 --- /dev/null +++ b/docs/build.rb @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# Build the dependency-free, static GitHub Pages site from the HTML fragments +# in _src. Run from anywhere with: ruby docs/build.rb +require 'erb' + +site_dir = __dir__ +source_dir = File.join(site_dir, '_src') +layout = ERB.new(File.read(File.join(source_dir, 'layout.erb')), trim_mode: '-') + +pages = { + 'index' => ['Ruby Facets | More of Ruby, one method at a time', + 'Ruby Facets adds focused extensions to Ruby core classes and the standard library.'], + 'learn' => ['Guide | Ruby Facets', + 'Install Ruby Facets and choose exactly which extensions to load.'], + 'news' => ['Releases | Ruby Facets', + 'Recent Ruby Facets releases and the historical news archive.'], + 'source' => ['Contribute | Ruby Facets', + 'Explore the source, report issues, and contribute to Ruby Facets.'] +} + +pages.each do |slug, (title, description)| + content = File.read(File.join(source_dir, "#{slug}.erb")) + active = slug + root = '' + output = layout.result(binding) + File.write(File.join(site_dir, "#{slug}.html"), output) +end + +# Historical posts keep their original article copy, but use today's site shell. +archive = { + '2008-01-01-how-facets-was-born' => 'How Facets Was Born', + '2008-03-24-release-2-4' => 'Facets 2.4.3', + '2009-07-21-new-website' => 'New Website with Jekyll', + '2009-08-22-release-2-7' => 'Facets 2.7 is a Significant Release', + '2009-11-09-release-2-8' => 'Facets 2.8 Release', + '2010-09-01-release-2-9' => 'Facets 2.9 Release' +} + +archive.each do |slug, post_title| + body = File.read(File.join(source_dir, 'archive', "#{slug}.html")) + date = slug[0, 10] + title = "#{post_title} | Ruby Facets archive" + description = "#{post_title}, a historical post from the Ruby Facets archive." + active = 'news' + root = '../' + content = <<~HTML +

FROM THE ARCHIVE / #{date}

#{post_title}

This post is preserved from an earlier Facets release. For current installation and API guidance, use the guide.

+
#{body}
+ + HTML + output = layout.result(binding) + File.write(File.join(site_dir, 'posts', "#{slug}.html"), output) +end diff --git a/docs/index.html b/docs/index.html index 1eceed5ae..cc8457bb8 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,191 +1,100 @@ - - - - + + - - - Ruby Facets - - - - - - - - - - - - - - - - - - + + + + + Ruby Facets | More of Ruby, one method at a time + + + - - - - -
- - - - - -
- -
-