{"id":17244961,"url":"https://github.com/ujihisa/rant","last_synced_at":"2026-03-05T23:42:19.295Z","repository":{"id":664390,"uuid":"307451","full_name":"ujihisa/rant","owner":"ujihisa","description":"Ruby Imperative Random Data Generator and Quickcheck","archived":false,"fork":false,"pushed_at":"2009-09-15T05:42:05.000Z","size":89,"stargazers_count":1,"open_issues_count":0,"forks_count":16,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-02-15T06:23:52.251Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"hayeah/rantly","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ujihisa.png","metadata":{"files":{"readme":"README.textile","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":"2009-09-15T05:38:55.000Z","updated_at":"2012-12-13T01:20:34.000Z","dependencies_parsed_at":null,"dependency_job_id":"bd45f8df-c0a2-4b58-962d-583f3d8fb472","html_url":"https://github.com/ujihisa/rant","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ujihisa/rant","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ujihisa%2Frant","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ujihisa%2Frant/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ujihisa%2Frant/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ujihisa%2Frant/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ujihisa","download_url":"https://codeload.github.com/ujihisa/rant/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ujihisa%2Frant/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30156180,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-05T22:39:40.138Z","status":"ssl_error","status_checked_at":"2026-03-05T22:39:24.771Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2024-10-15T06:28:10.892Z","updated_at":"2026-03-05T23:42:19.277Z","avatar_url":"https://github.com/ujihisa.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"h1. Imperative Random Data Generator and Quickcheck\n\nYou can use Rant to generate random test data, and use its Test::Unit extension for property-based testing.\n\nRant is basically a recursive descent interpreter, each of its method returns a random value of some type (string, integer, float, etc.).\n\nIts implementation has no alien mathematics inside. Completely side-effect-free-free.\n\nh1. Install\n\n\u003cpre\u003e\u003ccode\u003e\n$ gem install hayeah-rant --source http://gems.github.com\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cpre\u003e\u003ccode\u003e\n$ irb\n\u003e gem 'rant'\n\u003e require 'rant'\n\u003e Rant.gen.value { [integer,float] }\n=\u003e [20991307, 0.025756845811823]\n\u003e Rant.gen.value { [integer,float]}\n=\u003e [-376856492, 0.452245765751706]\n\u003c/code\u003e\u003c/pre\u003e\n\n\nh1. Data Generation\n\nYou can create random generators from the Rant class. Rant.gen is just returns a class instance of Rant.\n\n\u003cpre\u003e\u003ccode\u003e\n\u003e gen = Rant.new\n\u003e gen.value { [integer,float] }\n=\u003e [-163260081, 0.356075765934108]\n\u003c/code\u003e\u003c/pre\u003e\n\nh2. Getting Random Data Values\n\n\u003cpre\u003e\u003ccode\u003e\nRant#each(n,limit=10)\n  call a random block n times\nRant#map(n,limit=10)\n  call the generator n times, and collect values\nRant#inject and other Enumerable methods\n  ditto\nRant#value(limit=10)\n  call a random block once, and get its value.\n\u003c/code\u003e\u003c/pre\u003e\n\nTo collect an array of random data,\n\n\u003cpre\u003e\u003ccode\u003e\n# we want 5\n\u003e gen.map(5) { integer }\n=\u003e [-380638946, -29645239, 344840868, 308052180, -154360970]\n\u003c/code\u003e\u003c/pre\u003e\n\nTo iterate over random data,\n\n\u003cpre\u003e\u003ccode\u003e\n\u003e gen.each(5) { puts integer }\n296971291\n504994512\n-402790444\n113152364\n502842783\n=\u003e nil\n\u003c/code\u003e\u003c/pre\u003e\n\nTo get one value of random data,\n\n\u003cpre\u003e\u003ccode\u003e\n\u003e gen.value { integer }\n=\u003e 278101042\n\u003c/code\u003e\u003c/pre\u003e\n\nThe optional argument @limit@ is used with generator guard. By default, if you want to generate n items, the generator tries at most n * 10 times.\n\nThis almost always succeeds,\n\n\u003cpre\u003e\u003ccode\u003e\n\u003e gen.map(5) { i = integer; guard i \u003e 0; i }\n=\u003e [511765059, 250554234, 305947804, 127809156, 285960387]\n\u003c/code\u003e\u003c/pre\u003e\n\nThis always fails,\n\n\u003cpre\u003e\u003ccode\u003e\n\u003e gen.map(10) { guard integer.is_a?(Float) }\nRant::TooManyTries: Exceed gen limit 100: 101 failed guards)\n\u003c/code\u003e\u003c/pre\u003e\n\nh2. Random Generating Methods\n\nThe API is similiar to QuickCheck, but not exactly the same. In particular @choose@ picks a random element from an array, and @range@ picks a integer from an interval.\n\nh3. Simple Randomness\n\n\u003cpre\u003e\u003ccode\u003e\nRant#integer(n=nil)\n  random positive or negative integer. Fixnum only.\nRant#range(lo,hi)\n  random integer between lo and hi.\nRant#float\n  random float\nRant#bool\n  true or false\nRant#literal(value)\n  No-op. returns value.\nRant#choose(*vals)\n  Pick one value from among vals.\n\u003c/code\u003e\u003c/pre\u003e\n\nh3. Meta Randomness\n\nA rant generator is just a mini interpreter. It's often useful to go meta,\n\n\u003cpre\u003e\u003ccode\u003e\nRant#call(gen)\n  If gen is a Symbol, just do a method call with send.\n  If gen is an Array, the first element of the array is the method name, the rest are args.\n  If gen is a Proc, instance_eval it with the generator.\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cpre\u003e\u003ccode\u003e\n\u003e gen.value { call(:integer) }\n=\u003e -240998958\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cpre\u003e\u003ccode\u003e\n\u003e gen.value { call([:range,0,10]) }\n=\u003e 2\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cpre\u003e\u003ccode\u003e\n\u003e gen.value { call(Proc.new { [integer] })}\n=\u003e [522807620]\n\u003c/code\u003e\u003c/pre\u003e\n\nThe @call@ method is useful to implement other abstractions (See next subsection).\n\n\u003cpre\u003e\u003ccode\u003e\nRant#branch(*args)\n  Pick a random arg among args, and Rant#call it.\n\u003c/code\u003e\u003c/pre\u003e\n\n50-50 chance getting an integer or float,\n\n\u003cpre\u003e\u003ccode\u003e\n\u003e gen.value { branch :integer, :float }\n=\u003e 0.0489446702931332\n\u003e gen.value { branch :integer, :float }\n=\u003e 494934533\n\u003c/code\u003e\u003c/pre\u003e\n\n\nh3. Frequencies\n\n\u003cpre\u003e\u003ccode\u003e\nRant#freq(*pairs)\n  Takes a list of 2-tuples, the first of which is the weight, and the second a Rant#callable value, and returns a random value picked from the pairs. Follows the distribution pattern specified by the weights.\n\u003c/code\u003e\u003c/pre\u003e\n\nTwice as likely to get a float than integer. Never gets a ranged integer.\n\n\u003cpre\u003e\u003ccode\u003e\n\u003e gen.value { freq [1,:integer], [2,:float], [0,:range,0,10] }\n\u003c/code\u003e\u003c/pre\u003e\n\nIf the \"pair\" is not an array, but just a symbol, @freq@ assumes that the weight is 1.\n\n\u003cpre\u003e\u003ccode\u003e\n# 50-50 between integer and float\n\u003e gen.value { freq :integer, :float }\n\u003c/code\u003e\u003c/pre\u003e\n\nIf a \"pair\" is an Array, but the first element is not an Integer, @freq@ assumes that it's a Rant method-call with arguments, and the weight is one.\n\n\u003cpre\u003e\u003ccode\u003e\n# 50-50 chance generating integer limited by 10, or by 20.\n\u003e gen.value { freq [:integer,10], [:integer 20] }\n\u003c/code\u003e\u003c/pre\u003e\n\n\n\nh3. Sized Structure\n\nA Rant generator keeps track of how large a datastructure it should generate with its @size@ attribute.\n\n\u003cpre\u003e\u003ccode\u003e\nRant#size\n returns the current size\nRant#sized(n,\u0026block)\n sets the size for the duration of recursive call of block. Block is instance_eval with the generator.\n\u003c/code\u003e\u003c/pre\u003e\n\nRant provides two methods that depends on the size\n\n\u003cpre\u003e\u003ccode\u003e\nRant#array(*branches)\n  returns a sized array consisted of elements by Rant#calling random branches.\nRant#string(char_class=:print)\n  returns a sized random string, consisted of only chars from a char_class.\n\u003c/code\u003e\u003c/pre\u003e\n\nThe avaiable char classes for strings are:\n\n\u003cpre\u003e\u003ccode\u003e\n:alnum\n:alpha\n:blank\n:cntrl\n:digit\n:graph\n:lower\n:print\n:punct\n:space\n:upper\n:xdigit\n:ascii\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cpre\u003e\u003ccode\u003e\n# sized 10 array of integer or float\n\u003e gen.value { sized(10) { array(:integer,:float)}}\n=\u003e [417733046, -375385433, 0.967812380000118, 26478621, 0.888588160450082, 250944144, 305584916, -151858342, 0.308123867823313, 0.316824642414253]\n\n# fails if you forget to set the size.\n\u003e gen.value { array(:integer,:float)}\nRuntimeError: size not set\n\n\u003c/code\u003e\u003c/pre\u003e\n\nIf you set the size once, it applies to all subsequent recursive structures. Here's a sized 10 array of sized 10 strings,\n\n\u003cpre\u003e\u003ccode\u003e\n\u003e gen.value { sized(10) { array(:string)} }\n=\u003e [\"1c}C/,9I#}\", \"hpA/UWPJ\\\\j\", \"H'~ERtI`|]\", \"%OUaW\\\\%uQZ\", \"Z2QdY=G~G!\", \"H\u003co|\u003cFARGQ\", \"g\u003eojnxGDT3\", \"]a:L[B\u003ebhb\", \"_Kl=\u0026{tH^\u003c\", \"ly]Yfb?`6c\"]\n\u003c/code\u003e\u003c/pre\u003e\n\nOr a sized 10 array of sized 5 strings,\n\n\u003cpre\u003e\u003ccode\u003e\n\u003e gen.value { sized(10) { array Proc.new {sized(5) {string}}}}\n=\u003e [\"S\\\"jf \", \"d\\\\F-$\", \"-_8pa\", \"IN0iF\", \"SxRV$\", \".{kQ7\", \"6\u003e;fo\", \"}.D8)\", \"P(tS'\", \"y0v/v\"]\n\u003c/code\u003e\u003c/pre\u003e\n\nRant#array actually just delegate to Rant#freq, so you can use freq pairs:\n\n\u003cpre\u003e\u003ccode\u003e\n\u003e gen.value { sized(10) {array [1,:integer],[2,:float] }}\n=\u003e [0.983334733158678, -418176338, 0.976947175363592, 0.703390570421286, -478680395, 5483631, 0.966944106783513, 110469205, 0.540859146793544, 0.521813810037025]\n\u003c/code\u003e\u003c/pre\u003e\n\n\nh1. Property Testing\n\nRant extends Test::Unit for property testing. The extension is in its own module. So you need to require it.\n\n\u003cpre\u003e\u003ccode\u003e\nrequire 'rant/check'\n\u003c/code\u003e\u003c/pre\u003e\n\nIt defines,\n\n\u003cpre\u003e\u003ccode\u003e\nTest::Unit::Assertions#property_of(\u0026block)\n  The block is used to generate random data with a generator. The method returns a Rant::Property instance, that has the method 'check'.\n\u003c/code\u003e\u003c/pre\u003e\n\nIt's like this, using the gem 'shoulda'\n\n\u003cpre\u003e\u003ccode\u003e\n# checks that integer only generates fixnum.\nshould \"generate Fixnum only\" do\n   property_of  { integer }.check { |i| assert i.is_a?(Integer) }\nend\n\u003c/code\u003e\u003c/pre\u003e\n\nThe check block takes the generated data as its argument. One idiom I find useful is to include a parameter of the random data for the check argument. For example, if I want to check that Rant#array generates the right sized array, I could say,\n\n\u003cpre\u003e\u003ccode\u003e\nshould \"generate right sized array\" do\n  property_of {\n    len = integer\n    [len,sized(len) { array :integer }]\n  }.check { |(len,arr)|\n    assert_equal len, arr.length\n  }\nend\n\u003c/code\u003e\u003c/pre\u003e\n\nThat's about it. Enjoy :)\n\n\nh1. Copyright\n\nCopyright (c) 2009 Howard Yeh. See LICENSE for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fujihisa%2Frant","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fujihisa%2Frant","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fujihisa%2Frant/lists"}