{"id":21131161,"url":"https://github.com/wnameless/rubycollect4j","last_synced_at":"2025-07-09T01:33:40.539Z","repository":{"id":8004449,"uuid":"9412215","full_name":"wnameless/rubycollect4j","owner":"wnameless","description":"Ruby Collections for Java","archived":false,"fork":false,"pushed_at":"2024-12-22T15:47:28.000Z","size":2506,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-04T14:51:10.375Z","etag":null,"topics":["java","ruby","ruby-collections"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wnameless.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-04-13T10:45:05.000Z","updated_at":"2024-12-22T15:45:21.000Z","dependencies_parsed_at":"2023-01-13T14:36:12.686Z","dependency_job_id":null,"html_url":"https://github.com/wnameless/rubycollect4j","commit_stats":null,"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"purl":"pkg:github/wnameless/rubycollect4j","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wnameless%2Frubycollect4j","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wnameless%2Frubycollect4j/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wnameless%2Frubycollect4j/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wnameless%2Frubycollect4j/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wnameless","download_url":"https://codeload.github.com/wnameless/rubycollect4j/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wnameless%2Frubycollect4j/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264375597,"owners_count":23598413,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","ruby","ruby-collections"],"created_at":"2024-11-20T05:50:07.298Z","updated_at":"2025-07-09T01:33:40.518Z","avatar_url":"https://github.com/wnameless.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Maven Central](https://maven-badges.herokuapp.com/maven-central/net.sf.rubycollect4j/rubycollect4j/badge.svg)](https://maven-badges.herokuapp.com/maven-central/net.sf.rubycollect4j/rubycollect4j)\n[![codecov](https://codecov.io/gh/wnameless/rubycollect4j/branch/master/graph/badge.svg)](https://codecov.io/gh/wnameless/rubycollect4j)\n\n\nrubycollect4j\n=============\nRuby Collections for Java.\n\nThe rubycollect4j implements all methods refer to Ruby Array, Hash, Set, Enumerable, Enumerator, Range and String.\nIt also implements parts of Ruby Dir, File and Date methods.\n\nFor further information, please visit http://ruby-doc.org website.\n\n# Maven Repo\n``` xml\n\u003cdependency\u003e\n  \u003cgroupId\u003enet.sf.rubycollect4j\u003c/groupId\u003e\n  \u003cartifactId\u003erubycollect4j\u003c/artifactId\u003e\n  \u003cversion\u003e${newestVersion}\u003c/version\u003e\n  \u003c!-- Newest version shows in the maven-central badge above --\u003e\n\u003c/dependency\u003e\n```\n| Java required | Since version | Java Module supported\n| --- | --- | --- |\n| 11  | 3.x.x | Y |\n| 1.8 | 2.x.x | Y(2.1.x)|\n| 1.6 | 1.x.x | N |\n\n## Quick Demo\n```java\n// Sorts the characters by its frequency based on the word 'Mississippi' case-insensitively.\nRubyString word = Ruby.String.of(\"Mississippi\"); // Equivalent to new RubyString(\"Mississippi\")\nString result = word.map(String::toLowerCase).sortBy(c -\u003e word.count(c)).uniq().join();\n\nRuby.Kernel.p(result);\n// Output: \"mpis\"\n```\n\n## Introducing v2.x.x\n\nClass Ruby has been introduced.\u003cbr/\u003e\nIt provides a convenient approach to access the numerous features of RubyCollect4J.\u003cbr/\u003e\nAll static classes and methods under Ruby class are well documented, feel free to try them by yourself.\n\nDemo Ruby:\n```java\nRuby.Array.copyOf(Arrays.asList(1, 2, 3, 4)).minmax().join();\n// \"14\"\n\nRuby.Hash.of(\"a\", 1, \"b\", 2, \"c\", 3).transformValues(v -\u003e v * 2);\n// {\"a\"=2, \"b\"=4, \"c\"=6}\n\nRuby.Entry.of(\"xyz\", 321);\n// xyz=321\n\nRuby.Set.of(1, 2, 3, 4).divide(i -\u003e i % 2 == 0);\n// [[1, 3], [2, 4]]\n\nRuby.Enumerator.of(Arrays.asList(1, 2, 3, 4)).inject((x, y) -\u003e x * y);\n// 24\n\nRuby.LazyEnumerator.of(Arrays.asList(1,2,3,4)).cycle().first(10);\n// [1, 2, 3, 4, 1, 2, 3, 4, 1, 2]\n\nRuby.String.of(\"abcde\").tr(\"a-c\", \"z\");\n// \"zzzde\"\n\nRuby.Range.of(1, 100).sum();\n// 5050\n\nRuby.Dir.glob(\"./**/*\");\n// [file_1, dir_1, ...]\n\nRuby.File.foreach(\"/usr/share/dict/web2\").drop(99).first();\n// \"Abbadide\"\n\nRuby.Date.today().onWeekdayʔ();\n// true or false\n\nRuby.Object.isBlank(Collections.emptyList());\n// true\n\nRuby.Kernel.p(new char[] { 'a', 'b', 'c' });\n// ['a', 'b', 'c']\n```\n\n## v2.0.0 Changelog\nMost of the functions of v1.9.x are also avaliable in v2.0.x.\u003cbr/\u003e\nHere is the comparision list of static method names:\n\n|v2.0.x                     |v1.9.x                                   |\n|---------------------------|-----------------------------------------|\n|                           |(net.sf.rubycollect4j.RubyCollections.*) |\n|Ruby.Array.create          |                                         |\n|Ruby.Array.of              |ra                                       |\n|Ruby.Array.copyOf          |newRubyArray                             |\n|                           |                                         |\n|Ruby.Hash.create           |Hash                                     |\n|Ruby.Hash.of               |rh                                       |\n|Ruby.Hash.copyOf           |newRubyHash                              |\n|                           |                                         |\n|Ruby.Entry.of              |hp                                       |\n|                           |                                         |\n|Ruby.Set.create            |                                         |\n|Ruby.Set.of                |                                         |\n|Ruby.Set.copyOf            |newRubySet                               |\n|                           |                                         |\n|Ruby.Enumerator.of         |                                         |\n|Ruby.Enumerator.copyOf     |newRubyEnumerator                        |\n|                           |                                         |\n|Ruby.LazyEnumerator.of     |                                         |\n|Ruby.LazyEnumerator.copyOf |newRubyLazyEnumerator                    |\n|                           |                                         |\n|Ruby.String.create         |                                         |\n|Ruby.String.of             |rs                                       |\n|                           |                                         |\n|Ruby.Range.of              |range                                    |\n|                           |                                         |\n|Ruby.Date.of               |date                                     |\n|                           |                                         |\n|Ruby.Object.isBlank        |isBlank                                  |\n|Ruby.Object.isPresent      |isNotBlank                               |\n|                           |(end of RubyCollections.*)               |\n|Ruby.File.open             |RubyFile.open                            |\n|                           |                                         |\n|Ruby.Dir.open              |RubyDir.open                             |\n|                           |                                         |\n|Ruby.Kernel.p              |RubyKernel.p                             |\n\nRubyEnumerable has been changed from an abstract class into an interface due to the default methods feature of Java 8.\n\n## Examples:\n\nSince v1.9.0, RubyIterables \u0026 RubyStrings are added, they are simply utility classes just like java.util.Arrays.\u003cbr/\u003e\nThey provide the Ruby style ways to manipulate any Iterable and String (or CharSequence).\n\nHighly recommended to use with the @ExtensionMethod of [Project Lombok](https://projectlombok.org/).\n```java\nIterable\u003cInteger\u003e ints = Arrays.asList(3, 6, 7, 2);\nint max = RubyIterables.max(ints);\nSystem.out.println(max);   // Output: 7\n\nString trStr = RubyStrings.tr(\"Mississippi\", \"i\", \"I\");\nSystem.out.println(trStr); // Output: MIssIssIppI\n```\n\nPlease add following lines before running examples:\n```java\nimport static net.sf.rubycollect4j.RubyKernel.p;\n```\n\nDemo RubyArray:\n```java\np( Ruby.Array.of(1, 2, 3, 4) );                         // Output: [1, 2, 3, 4]\np( Ruby.Array.of(Ruby.Array.of(1, 2)) );                           // Output: [[1, 2]]\nList\u003cInteger\u003e list = new ArrayList\u003cInteger\u003e();\nlist.add(1);\np( Ruby.Array.of(list) );                               // Output: [1]\nMap\u003cInteger, String\u003e map = new LinkedHashMap\u003cInteger, String\u003e();\nmap.put(1, \"a\");\nmap.put(2, \"b\");\n// Any Iterable or Iterator object can be converted into RubyArray.\np( Ruby.Array.of(map.values) );                         // Output: [a, b]\n// RubyArray is Comparable if the elements are Comparable.\np( Ruby.Array.of(Ruby.Array.of(3, 4), Ruby.Array.of(1, 2)).sort() );          // Output: [[1, 2], [3, 4]]\n// RubyArray is both a List and a Ruby.Enumerable.\np( Ruby.Array.of(1, 2, 3) instanceof List );            // Output: true\np( Ruby.Array.of(1, 2, 3) instanceof Ruby.Enumerable ); // Output: true\n```\n\n```java\n// By default, Ruby.Array.of() is just a wrapper to an existed List.\n// You can make a defensive copy by following codes.\nList\u003cInteger\u003e list = new ArrayList\u003cInteger\u003e();\nlist.add(1);\nRubyArray\u003cInteger\u003e ra = Ruby.Array.copyOf(list);\n```\n\nDemo RubyHash:\n```java\np(  Ruby.Hash.of(\"a\", 1, \"b\" ,2) );                        // Output: {a=1, b=2}\nMap\u003cString, Long\u003e map = new HashMap\u003cString, Long\u003e();\nmap.put(\"abc\", 123L);\n// Any Map can be converted into RubyHash.\np(  Ruby.Hash.copyOf(map) );                                   // Output: {abc=123}\n// hp() simply creates an Entry and the word 'hp' means hash pair\np( Hash(Ruby.Array.of(Ruby.Entry.of(\"a\", 1), Ruby.Entry.of(\"b\" ,2))) );          // Output: {a=1, b=2}\np( Hash(Ruby.Hash.of(\"a\", 1, \"b\", 2).toA()) );            // Output: {a=1, b=2}\n// The Entry of RubyHash is Comparable if the type of the key elements is Comparable.\np(  Ruby.Hash.of(4, 3, 2, 1).sort() );                     // Output: [2=1, 4=3]\n// RubyHash is both a Map and a Ruby.Enumerable.\np(  Ruby.Hash.of(1, 2, 3, 4) instanceof Map );             // Output: true\np(  Ruby.Hash.of(1, 2, 3, 4) instanceof Ruby.Enumerable ); // Output: true\n```\n\n```java\n// By default, Ruby.Hash.copyOf() makes a copy of input Map.\n// You can only wrap a LinkedHashMap up by following codes, because the keys of RubyHash need to be ordered.\nLinkedHashMap\u003cInteger, String\u003e map = new LinkedHashMap\u003cInteger, String\u003e();\nmap.put(1, \"a\");\nRubyHash\u003cInteger, String\u003e rh = Ruby.Hash.of(map);\n```\n\nDemo RubySet:\n```java\np( Ruby.Set.of(1, 2, 3, 3) );                                // Output: [1, 2, 3]\nList\u003cInteger\u003e list = new ArrayList\u003cInteger\u003e();\nlist.add(1);\nlist.add(1);\n// Any Iterable object can be converted into RubySet\np( Ruby.Set.copyOf(list) );                                      // Output: [1]\n// RubySet is Comparable if the elements are Comparable.\np( Ruby.Set.of(newRubySet(3, 4), newRubySet(1, 2)).sort() ); // Output: [[1, 2], [3, 4]]\n// RubySet is both a Set and a Ruby.Enumerable.\np( Ruby.Set.of(1, 2, 3, 3) instanceof Set );                 // Output: true\np( Ruby.Set.of(1, 2, 3, 3) instanceof Ruby.Enumerable );     // Output: true\n```\n\n```java\n// You can only wrap a LinkedHashSet up by following codes, because the elements of RubySet need to be ordered.\nLinkedHashSet\u003cInteger\u003e set = new LinkedHashSet\u003cInteger\u003e();\nset.add(1);\nRubySet\u003cInteger\u003e rubySet = Ruby.Set.of(set);\n```\n\nDemo RubyString:\n```java\n// RubyString can be created from any Object.\np( Ruby.String.of(1000L).count(\"0\") );                  // Output: 3\n// RubyString is also a RubyEnumerable of each character(as String).\np( Ruby.String.of(\"abc\").map(\"codePointAt\", 0) );                   // Output: [97, 98, 99]\n// RubyString implements fluent interface.\n// After multiple actions, you can turn it to a Java String by calling toS().\np( Ruby.String.of(\"ABC\").chop().capitalize().concat(\"001\").toS() ); // Output: Ab001\n// RubyString is both a CharSequence and a Ruby.Enumerable.\np( Ruby.String.of(\"abc\") instanceof CharSequence );                 // Output: true\np( Ruby.String.of(\"abc\") instanceof Ruby.Enumerable );              // Output: true\n```\n\nDemo abstract RubyEnumerable class:\n```java\n// You can simply make your class inherit all the RubyEnumerable methods by extending it.\npublic class YourIterableClass\u003cE\u003e extends RubyEnumerable\u003cE\u003e {\n  private final Iterable\u003cE\u003e iter;\n  \n  public YourIterableClass(Iterable\u003cE\u003e iter) { this.iter = iter; }\n  \n  @Override\n  protected Iterable\u003cE\u003e getIterable() { return iter; }\n}\n\n// The class which extends RubyEnumerable becomes a Ruby.Enumerable.\np( new YourIterableClass(iter) instanceof Ruby.Enumerable ); // Output: true\n```\n\nDemo RubyEnumerator:\n```java\nMap\u003cString, Long\u003e map = new LinkedHashMap\u003cString, Long\u003e() {{ put(\"a\", 1L); put(\"b\", 2L); put(\"c\", 3L); }};\n// Any Iterable object can be wrapped into RubyEnumerator.\nRubyEnumerator\u003cEntry\u003cString, Long\u003e\u003e re = Ruby.Enumerator.of(map.entrySet());\n// RubyEnumerator is much like RubyEnumerable, but it is both an Iterator and an Iterable.\np( re instanceof Ruby.Enumerator ); // Output: true\np( re instanceof Ruby.Enumerable ); // Output: true\np( re instanceof Iterator );        // Output: true\np( re instanceof Iterable );        // Output: true\n// It can 'peek' and 'rewind'.\np( re.peek() );                     // Output: a=1\np( re.next() );                     // Output: a=1\np( re.next() );                     // Output: b=2\np( re.peek() );                     // Output: c=3\nre.rewind();\np( re.next() );                     // Output: a=1\n```\n\n```java\n// By default, RubyEnumerator.of() is just a wrapper to an existed Iterable.\n// You can make a defensive copy by following codes.\nMap\u003cString, Long\u003e map = new LinkedHashMap\u003cString, Long\u003e() {{ put(\"a\", 1L); put(\"b\", 2L); put(\"c\", 3L); }};\nRubyEnumerator\u003cEntry\u003cString, Long\u003e\u003e re = Ruby.Enumerator.copyOf(map.entrySet());\n```\n\nDemo RubyLazyEnumerator:\n```java\nRubyLazyEnumerator rle = Ruby.LazyEnumerator.of(Arrays.asList(1, 2, 3, 4));\n// RubyLazyEnumerator is not a Ruby.Enumerable, but it is a Ruby.LazyEnumerator.\np( rle.drop(1) instanceof Ruby.LazyEnumerator );    // Output: true\np( rle instanceof Iterator );                       // Output: true\np( rle instanceof Iterable );                       // Output: true\np( rle.drop(1).toA() );                             // Output: [2, 3, 4]\n// A RubyLazyEnumerator can also be created by RubyArray#lazy.\np( ra(1, 2, 3, 4).lazy().cycle().drop(6).first() ); // Output: 3\n```\n\n```java\n// By default, RubyLazyEnumerator.of() is just a wrapper to an existed Iterable.\n// You can make a defensive copy by following codes.\nMap\u003cString, Long\u003e map = new LinkedHashMap\u003cString, Long\u003e() {{ put(\"a\", 1L); put(\"b\", 2L); put(\"c\", 3L); }};\nRubyLazyEnumerator\u003cEntry\u003cString, Long\u003e\u003e re = Ruby.LazyEnumerator.copyOf(map.entrySet());\n```\n\nDemo RubyRange:\n```java\np( Ruby.Range.of(1, 5).toA() );                                   // Output: [1, 2, 3, 4, 5]\np( Ruby.Range.of(\"Z\", \"AB\").toA() );                              // Output: [Z, AA, AB]\np( Ruby.Range.of(\"ZZ-999\", \"AAA-001\").toA() );                    // Output: [ZZ-999, AAA-000, AAA-001]\np( Ruby.Range.of(1.08, 1.1).toA() );                              // Output: [1.08, 1.09, 1.10]\np( Ruby.Range.of(\"1.08\", \"1.1\").toA() );                          // Output: [1.08, 1.09, 1.10]\np( Ruby.Range.of(Ruby.Date.of(2013, 06, 30), Ruby.Date.of(2013, 07, 01)).toA() ); // Output: [Sun Jun 30 00:00:00 CST 2013, Mon Jul 01 00:00:00 CST 2013]\n\n// RubyRange accepts any Temporal objects and TemporalUnit(ChronoUnit) of Java 8\np( Ruby.Range.of(LocalDateTime.now(), LocalDateTime.now().plusDays(7), ChronoUnit.DAYS).toA().size() )    // Output: 8\np( Ruby.Range.of(LocalDateTime.now(), LocalDateTime.now().plusDays(7), ChronoUnit.SECONDS).toA().size() ) // Output: 604801\n```\n\nDemo RubyDate:\n```java\np( Ruby.Date.of(2013, 7, 1).add(10).days() );          // Output: Thu Jul 11 00:00:00 CST 2013\np( Ruby.Date.of(2013, 7, 1, 21).minus(30).minutes() ); // Output: Mon Jul 01 20:30:00 CST 2013\np( Ruby.Date.of(2013, 7, 7, 16, 15, 14).endOfDay() );  // Output: Sun Jul 07 23:59:59 CST 2013\np( Ruby.Date.of(2013, 7, 11).beginningOfWeek() );      // Output: Sun Jul 07 00:00:00 CST 2013\np( RubyDate.today() );                         // Output: date of today\np( RubyDate.yesterday() );                     // Output: date of yesterday\nCalendar c = Calendar.getInstance();\nc.clear();\np( Ruby.Date.of(c.getTime()) );                        // Output: Thu Jan 01 00:00:00 CST 1970\np( Ruby.Date.of(2014, 5, 1).beginningOfQuarter() );    // Output: Tue Apr 01 00:00:00 CST 2014\n```\n\nDemo RubyObject:\n```java\nRubyHash\u003cString, String\u003e profile = Ruby.Hash.of(\"Name\", \"John Doe\", \"Gender\", \"Male\", \"Birthday\", \"2001/10/01\");\n// Assumes Object person has 3 setters: setName, setGender, setBirthday.\nprofile.each((key, value) -\u003e Ruby.Object.send(person, \"set\" + key, value));\n// As you can see, Ruby.Object.send() is a wrapper to Java Reflection.\n```\n\nDemo RubyLiterals:\n```java\np( Ruby.Literals.qw(\"a bc def\") ); // Output: [a, bc, def]\np( Ruby.Literals.qx(\"echo\", \"hello\") ); // Output: hello\np( Ruby.Literals.qr(\"^\\\\d+$\").matcher(\"123\").find() ); // Output: true\n```\n\nDemo RubyDir:\n```text\nfolder1\n       /folder1-1\n                 /file1-1-1\n                 /file1-1-2\n       /folder1-2\n                 /file1-2-1\n                 /file1-2-2\n                 /file1-2-3\n       /file1-1\n       /file1-2\n       /file1-3\n       /file1-4\n```\n\n```java\np( Ruby.Dir.glob(\"folder1/*\").sort() );                 // Output: [file1-1, file1-2, file1-3, file1-4, folder1-1, folder1-2]\np( Ruby.Dir.glob(GLOB_DIR + \"**/*1-*-1*\").sort() );     // Output: [folder1/folder1-1/file1-1-1, folder1/folder1-2/file1-2-1]\np( Ruby.Dir.glob(GLOB_DIR + \"folder1/*[2,3]\").sort() ); // Output: [file1-2, file1-3, folder1-2]\n```\n\nDemo RubyFile:\n```java\nRubyFile rf = Ruby.File.open(\"test.txt\", \"r+\");\nrf.puts(\"a\");\nrf.puts(\"bc\");\nrf.puts(\"def\");\nrf.close();\nrf = RubyFile.open(\"test.txt\", \"r\");\np( rf.eachLine().toA() );                         // Output: [a, bc, def]\nrf.close();\n// The method foreach() closes the stream automatically.\nRuby.File.foreach(\"test.txt\", new Block\u003cString\u003e() {\n  public void yield(String item) {\n    System.out.print( item );\n  }\n});                                               // Output: abcdef\np( Ruby.File.join(\"/home/\", \"/ruby\", \"collect\") ); // Output: \"/home/ruby/collect\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwnameless%2Frubycollect4j","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwnameless%2Frubycollect4j","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwnameless%2Frubycollect4j/lists"}