{"id":15688404,"url":"https://github.com/marioruiz/nice_hash","last_synced_at":"2025-05-07T13:46:14.060Z","repository":{"id":56885514,"uuid":"134287216","full_name":"MarioRuiz/nice_hash","owner":"MarioRuiz","description":"You can easily generate all the hashes you want following the criteria you specify. Many other features coming to Hash class like the methods 'bury' or select_key, access the keys like methods: my_hash.my_key.other_key. You will be able to generate thousands of different hashes just declaring one and test easily APIs based on JSON for example.","archived":false,"fork":false,"pushed_at":"2024-03-19T12:50:47.000Z","size":158,"stargazers_count":9,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-16T21:25:21.519Z","etag":null,"topics":["api","generation","hash","json","nicehash","pattern","random","ruby","ruby-gem","string","testing"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MarioRuiz.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-05-21T15:22:45.000Z","updated_at":"2024-12-30T00:37:48.000Z","dependencies_parsed_at":"2024-03-15T16:50:18.192Z","dependency_job_id":"5d25e4e9-2b89-457f-b8be-10860811e74b","html_url":"https://github.com/MarioRuiz/nice_hash","commit_stats":{"total_commits":88,"total_committers":5,"mean_commits":17.6,"dds":"0.045454545454545414","last_synced_commit":"6b66639d3d655518e7b761e92cf659688beb95c0"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarioRuiz%2Fnice_hash","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarioRuiz%2Fnice_hash/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarioRuiz%2Fnice_hash/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarioRuiz%2Fnice_hash/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MarioRuiz","download_url":"https://codeload.github.com/MarioRuiz/nice_hash/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252890008,"owners_count":21820288,"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":["api","generation","hash","json","nicehash","pattern","random","ruby","ruby-gem","string","testing"],"created_at":"2024-10-03T17:59:28.722Z","updated_at":"2025-05-07T13:46:14.041Z","avatar_url":"https://github.com/MarioRuiz.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NiceHash\n\n[![Gem Version](https://badge.fury.io/rb/nice_hash.svg)](https://rubygems.org/gems/nice_hash)\n[![Build Status](https://travis-ci.com/MarioRuiz/nice_hash.svg?branch=master)](https://github.com/MarioRuiz/nice_hash)\n[![Coverage Status](https://coveralls.io/repos/github/MarioRuiz/nice_hash/badge.svg?branch=master)](https://coveralls.io/github/MarioRuiz/nice_hash?branch=master)\n![Gem](https://img.shields.io/gem/dt/nice_hash)\n![GitHub commit activity](https://img.shields.io/github/commit-activity/y/MarioRuiz/nice_hash)\n![GitHub last commit](https://img.shields.io/github/last-commit/MarioRuiz/nice_hash)\n![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/MarioRuiz/nice_hash)\n\n\nNiceHash creates hashes following certain patterns so your testing will be much easier.\n\nYou can easily generate all the hashes you want following the criteria you specify. \n\nMany other features coming to Hash class like the methods 'bury' or select_key, access the keys like methods: my_hash.my_key.other_key. You will be able to generate thousands of different hashes just declaring one and test easily APIs based on JSON for example.\n\nYou can also parse and filter a json string very easily.\n\nTo generate the strings following a pattern take a look at the documentation for string_pattern gem: https://github.com/MarioRuiz/string_pattern. Using string_pattern you can also generate Spanish or English words. We added support for generating strings from regular expressions but it is only working for the ´generate´ method, use it with caution since it is still on an early stage of development.\n\nTo use nice_hash on Http connections take a look at nice_http gem: https://github.com/MarioRuiz/nice_http\n\n## Table of contents\n- [Installation](#installation)\n- [Usage](#usage)\n  * [How to access the different keys](#how-to-access-the-different-keys)\n  * [Change all values on the keys we specified](#change-all-values-on-the-keys-we-specified)\n  * [Filtering / Selecting an specific key on the hash and subhashes](#filtering---selecting-an-specific-key-on-the-hash-and-subhashes)\n  * [How to generate the hash with the criteria we want](#how-to-generate-the-hash-with-the-criteria-we-want)\n  * [How to generate the hash with wrong values for the string patterns specified on the hash](#how-to-generate-the-hash-with-wrong-values-for-the-string-patterns-specified-on-the-hash)\n  * [Return the select_fields or the pattern_fields](#return-the-select-fields-or-the-pattern-fields)\n  * [dig and bury Hash methods](#dig-and-bury-hash-methods)\n  * [Validating hashes](#validating-hashes)\n  * [Change only one value at a time and return an Array of Hashes](#change-only-one-value-at-a-time-and-return-an-array-of-hashes)\n  * [Adding other values on run time when calling `generate` method](#adding-other-values-on-run-time-when-calling--generate--method)\n    + [Accessing other values of the hash on run time](#accessing-other-values-of-the-hash-on-run-time)\n  * [Compare the structure of a replica with the supplied structure](#compare-the-structure-of-a-replica-with-the-supplied-structure)\n  * [Other useful methods](#other-useful-methods)\n    + [Time stamp](#time-stamp)\n    + [Random dates](#random-dates)\n    + [Deep copy of a hash](#deep-copy-of-a-hash)\n    + [Nested deletion](#nested-deletion)\n    + [Deep merge of two hashes](#deep-merge-of-two-hashes)\n    + [Boolean class](#boolean-class)\n  * [Other tools integration](#other-tools-integration)\n    + [Tabulo](#tabulo)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'nice_hash'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install nice_hash\n\n## Usage\n\nRemember!! To generate the strings following a pattern take a look at the documentation for string_pattern gem: https://github.com/MarioRuiz/string_pattern. You can also generate Spanish or English words. We added support for generating strings from regular expressions but it is only working for the ´generate´ method, use it with caution since it is still on an early stage of development. All you have to do is to add to a key the value as a Regular expression, for example the key uuid in here will generate a random value like this: \"E0BDE5B5-A738-49E6-83C1-9D1FFB313788\"\n\n```ruby\nmy_hash = { \n    uuid: /[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}/, \n    key: \"Wsdf88888\",\n    doomId: :\"10:N\"\n}    \n```\n\nThis is the Hash we will be using on our examples:\n\n```ruby\n\nrequire 'nice_hash'\nStringPattern.word_separator = ' '\n\nmy_hash={\n    loginame: :\"5-10:/xn/\", \n    [:pwd1, :pwd2, :pwd3] =\u003e :\"5-10:L/n/\",\n    name: :\"10-20:T_/x/\",\n    age: 18..120,\n    euros: 0.0..3000.0,\n    created: DateTime,\n    customer: Boolean,\n    draws: [\n        {\n            drawId: :\"5:N\",\n            drawName: :\"10:Ln\",\n            type: :\"Weekely|Daily\",\n            owner: {\n                default: 'admin',\n                correct: :\"20:L\"\n            }\n        },\n        {\n            drawId: :\"5:N\",\n            drawName: :\"10:Ln\",\n            type: :\"Weekely|Daily\",\n            owner: {\n                default: 'admin',\n                correct: :\"20:L\"\n            }\n        }\n    ],\n    zip: {default: '00000', correct: :'5:N'},\n    address: \"21 Doom Av\",\n    city: {\n            default: \"Madrid\",\n            correct: \"London|Rome\"\n    },\n    wagers: ['34AAB', 'dfffDD', '33499A'],\n    country: {default: 'Spain', correct: [\"Spain\", \"Iceland\", \"Serbia\", \"Denmark\", \"Canada\", \"Italy\", \"Austria\"].join(\"|\")}, #one of these values\n    mobilePhone: {default: '(987)654321', correct: ['(', :'3:N', ')', :'6-8:N']},\n    sex: :\"male|female|other\", #any of these values\n    display: true,\n    user_names: [ :'3-10:L' ]\n}\n```\n\nExplanations of the different fields:\n  \n    loginname: from 5 to 10 characters, mandatory to have lower letters and numbers\n    pwd, pwd2, pwd3: will have the same value. The value from 5 to 10 chars, optional capital and lower letters, necessary to contain numbers\n    name: from 10 to 20 chars. Optional national characters and space, necessary lower letters.\n    age: number from 18 to 120\n    euros: float number from 0.0 to 3000.0\n    created: Time stamp format, 2019-06-20T11:40:34.547Z\n    customer: Boolean, (true or false)\n    drawId: 5 numbers\n    drawName: 10 letters and/or numbers\n    type: 'Weekely' or 'Daily'\n    owner: correct: 20 letters\n    zip: correct: 5 numbers\n    city: correct: 'London' or 'Rome'\n    country: correct: one of these values \"Spain\", \"Iceland\", \"Serbia\", \"Denmark\", \"Canada\", \"Italy\", \"Austria\"\n    mobilePhone: correct: a sting pattern with one of the next: \"(nnn) nnnnnn\", \"(nnn) nnnnnnn\", \"(nnn) nnnnnnnn\"\n    sex: 'male' or 'female' or 'other'\n    user_names: array of strings from 3 to 10 letters\n\nSo in case you want to assign to a key a string pattern value like for example in loginame, you need to specify the string pattern as a symbol :\"5-10:/xn/\"\n\nYou can also supply an array of strings and string patterns, like on mobilePhone.correct: ['(', :'3:N', ')', :'6-8:N']}\n\nAlso you can specify to select one of the values you want by separating them with |, like for example on sex field: \"male|female|other\"\n\nIn case you want one pattern to be generated with unique values, so never repeat the same value for that particular pattern, use a symbol object pattern and add to the end of the pattern the symbol: \u0026\n\n```ruby\n\n    loginame: :\"5-10:/xn/\u0026\", \n\n```\n\nAlso if you have a JSON string you want to parse it and get the values of certain keys you can use the json method we added to nice_hash:\n\n```ruby\n    my_json_string=\"{\\\"id\\\":344,\\\"customer\\\":{\\\"name\\\":\\\"Peter Smith\\\",\\\"phone\\\":334334333},\\\"tickets\\\":[{\\\"idt\\\":345,\\\"name\\\":\\\"myFavor1\\\"},{\\\"idt\\\":3123},{\\\"idt\\\":3145,\\\"name\\\":\\\"Special ticket\\\"}]}\"\n    puts my_json_string.json(:idt)\n    #\u003e [345, 3123, 3145]\n\n    puts my_json_string.json(:idt, :name)\n    #\u003e {:name=\u003e[\"Peter Smith\", [\"myFavor1\", \"Special ticket\"]], :idt=\u003e[345, 3123, 3145]}\n```\n\nTo make easier to compare values by default it is setup SP_COMPARE_NUMBERS_AS_STRINGS = true, that will return true for example in these comparations:  \n* '300' == 300\n* '300.12' == 300.12\n* \"\" == nil  \n\nTo avoid that set SP_COMPARE_NUMBERS_AS_STRINGS = false before `require 'nice_hash'`  \nTake in consideration certain libraries (fex 'net/ldap') are failing if `SP_COMPARE_NUMBERS_AS_STRINGS` is set to true. Since NiceHash is modifying the String class.   \n\n\n### How to access the different keys\n\nYou can access the keys of the hash like always, but now we added to the Hash class the posibility of accessing it using:\n\n```ruby\n    puts my_hash[:address] # like usually is done\n    puts my_hash.address\n    my_hash.address = '99 Danish Street' #assignment\n    puts my_hash.loginame\n    puts my_hash.mobilePhone.correct\n    puts my_hash.draws[1].owner.correct\n```\nAlso another way to access the different keys is by adding first underscore. \nBy doing it this way we are avoiding the cases where already exists a method with the same name on Hash class, for example: zip, display, default, select... \n\n```ruby\n    puts my_hash._address\n    my_hash._address = '99 Danish Street' #assignment\n    my_hash._display = false #assignment\n    puts my_hash._loginame\n    puts my_hash._mobilePhone._correct\n    puts my_hash._draws[1]._owner._correct\n    puts my_hash._zip.correct #you can mix both also\n```\n\nBy using the string_pattern gem you can generate single strings following the specific pattern on the field:\n\n```ruby\n    puts my_hash.loginame.generate #\u003es93owuvkh\n    puts my_hash.mobilePhone.correct.generate #\u003e(039)5669558\n    puts my_hash._zip._correct.gen # gen is an alias for generate method #\u003e84584\n```\n\nIf you want to search for all the values of one or more keys use get_values method:\n\n```ruby\nnew_hash = my_hash.generate\nputs new_hash.get_values(:address) #\u003e {:address=\u003e\"21 Doom Av\"}\nputs new_hash.get_values(:address, :zip) #\u003e {:zip=\u003e{:default=\u003e\"00000\", :correct=\u003e\"42782\"}, :address=\u003e\"21 Doom Av\"}\nputs new_hash.get_values(:drawId) #\u003e {:drawId=\u003e[\"84914\", \"21158\"]}\n#using nested keys\nputs new_hash.get_values(:'draws.drawId') #\u003e {:'draws.drawId'=\u003e[\"84914\", \"21158\"]}\n```\n\nIn case of an array of hashes, you will be able also to access the different keys, for example:\n\n```ruby\nmy_array = [{name: 'Peter', city: 'Madrid'}, {name: 'Lola', city: 'NYC'}] :\n\nmy_array.city \n#\u003e ['Madrid', 'NYC']\n\nmy_array._name\n#\u003e ['Peter', 'Lola']\n```\n\n### Change all values on the keys we specified\n\nSupply a hash with all the keys and the values you want to change on the hash, then it will return the hash/array with the values modified at any level.\n\n```ruby\nmy_hash = {\n  path: \"/api/users\",\n  data: { \n      name: \"morpheus\", \n      job: \"leader\", \n      lab: { \n          doom: 'one', \n          beep: true, \n          name:'mario', \n          products: [ \n              {\n                  name: 'game', \n                  price: 30\n              },\n              {\n                  name: 'chair', \n                  price: 130\n              }\n            ] \n        }\n    }\n}\n\n# using NiceHash class\npp NiceHash.set_values(my_hash, { price: 75, beep: false } )\n\n# using the Hash class\npp my_hash.set_values({ price: 75, beep: false })\n\n# setting specific nested keys\npp my_hash.set_values({'data.lab.products.price': 75, 'data.lab.beep': false})\n\n```\n\n### Filtering / Selecting an specific key on the hash and subhashes\n\nIn case you supply different possibilities to be used like for example on fields: owner, zip, city and mobilePhone, and you one to use a concrete one, use the method select_key\n\n```ruby\n    #using NiceHash class\n    new_hash = NiceHash.select_key(my_hash, :correct)\n    #using select_key method on Hash class\n    new_hash = my_hash.select_key(:correct)\n    default_hash = my_hash.select_key(:default)\n```\n\nOn this example new_hash will contain: \n\n```ruby\n{\n    loginame: :\"5-10:/xn/\", \n    [:pwd1, :pwd2, :pwd3] =\u003e :\"5-10:L/n/\",\n    name: :\"10-20:T_/x/\",\n    age: 18..120,\n    euros: 0.0..3000.0,\n    created: DateTime,\n    customer: Boolean,\n    draws: [\n        {\n            drawId: :\"5:N\",\n            drawName: :\"10:Ln\",\n            type: :\"Weekely|Daily\",\n            owner: :\"20:L\"\n        },\n        {\n            drawId: :\"5:N\",\n            drawName: :\"10:Ln\",\n            type: :\"Weekely|Daily\",\n            owner: :\"20:L\"\n        }\n    ],\n    zip: :'5:N',\n    address: \"21 Doom Av\",\n    city: \"London|Rome\",\n    wagers: ['34AAB', 'dfffDD', '33499A'],\n    country: [\"Spain\", \"Iceland\", \"Serbia\", \"Denmark\", \"Canada\", \"Italy\", \"Austria\"].join(\"|\"), #one of these values\n    mobilePhone: ['(', :'3:N', ')', :'6-8:N'],\n    sex: :\"male|female|other\", #any of these values\n    display: true,\n    user_names: [ :'3-10:L' ]\n}\n```\n\nAlso you can filter the hash you want and return only the speficied keys by using the `nice_filter` method\n\n```ruby\n    my_hash = { user: {\n                        address: {\n                               city: 'Madrid',\n                               country: 'Spain'\n                            },\n                        name: 'Peter',\n                        age: 33,\n                        customers: [{name: 'Peter', currency: 'Euro'}, {name:'John', currency: 'Euro'}]\n                      },\n                customer: true\n    }\n    pp my_hash.nice_filter([:'user.address.city', :'customer', :'user.customers.name'])\n#\u003e  {:user=\u003e\n#\u003e    {:address=\u003e{:city=\u003e\"Madrid\"},\n#\u003e      :customers=\u003e[{:name=\u003e\"Peter\"}, {:name=\u003e\"John\"}]\n#\u003e    },\n#\u003e   :customer=\u003etrue\n#\u003e  }\n```\n\n### How to generate the hash with the criteria we want\n\nYou can use the 'generate' method and everytime will be generated a different hash with different values.\n\nRemember you can filter/select by a hash key\n\nUsing the NiceHash class:\n```ruby\n#without filtering\nnew_hash = NiceHash.generate(my_hash)\n#filtering by a key passing the key on parameters\nnew_hash = NiceHash.generate(my_hash, :correct)\n```\n\nUsing Hash class (you can use the alias 'gen' for 'generate'): \n```ruby\n#without filtering\nnew_hash = my_hash.generate\n#filtering by a key passing the key on parameters\nnew_hash = my_hash.generate(:correct)\n#filtering by a key using select_key method\nnew_hash = my_hash.select_key(:correct).generate\n```\n\n\nIn case of filtering by :correct new_hash would have a value like this for example:\n\n```ruby\n{:loginame=\u003e\"s45x029o\",\n :pwd1=\u003e\"E6hz9YS7\",\n :pwd2=\u003e\"E6hz9YS7\",\n :pwd3=\u003e\"E6hz9YS7\",\n :name=\u003e\"OyTQNfEyPOzVYMxPym\",\n :age=\u003e 19,\n :euros=\u003e 2133.34,\n :created=\u003e \"2019-06-20T11:40:34.547Z\",\n :customer=\u003e true,\n :draws=\u003e\n  [{:drawId=\u003e\"54591\",\n    :drawName=\u003e\"cr5Q7pq4G8\",\n    :type=\u003e\"Weekely\",\n    :owner=\u003e\"nKEasYWInPGJxxElBZUB\"},\n   {:drawId=\u003e\"73307\",\n    :drawName=\u003e\"FnHPM4CsRC\",\n    :type=\u003e\"Weekely\",\n    :owner=\u003e\"cNGpHDhDLcxSFbOGqvNy\"}],\n :zip=\u003e\"47537\",\n :address=\u003e\"21 Doom Av\",\n :city=\u003e\"London\",\n :wagers=\u003e[\"34AAB\", \"dfffDD\", \"33499A\"],\n :country=\u003e\"Denmark\",\n :mobilePhone=\u003e\"(707)8782080\",\n :sex=\u003e\"male\",\n :display=\u003etrue,\n :user_names=\u003e[\"FFrriNdw\", \"ACc\"]\n}\n```\n\nIn case no filtering you will get all the values for all keys\n\n### How to generate the hash with wrong values for the string patterns specified on the hash\n\nWe can generate wrong values passing the keyword argument: expected_errors (alias: errors)\n\nThe possible values you can specify is one or more of these ones: :length, :min_length, :max_length, :value, :required_data, :excluded_data, :string_set_not_allowed\n\n    :length: wrong length, minimum or maximum\n    :min_length: wrong minimum length\n    :max_length: wrong maximum length\n    :value: wrong resultant value\n    :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.\n    :excluded_data: the resultant string will include one or more characters that should be excluded. It works only if excluded data supplied on the pattern.\n    :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.\n\nExamples:\n\n```ruby\nwrong_values = my_hash.generate(:correct, expected_errors: [:value])\n\nwrong_max_length = my_hash.generate(:correct, errors: :max_length)\n\nwrong_min_length = my_hash.generate(:correct, expected_errors: :min_length)\n\nwrong_min_length = my_hash.select_key(:correct).generate(errors: :min_length)\n\nvalid_values = my_hash.generate(:correct)\n```\n\nOn this example wrong_min_length will contain something like:\n\n```ruby\n{:loginame=\u003e\"0u\",\n :pwd1=\u003e\"4XDx\",\n :pwd2=\u003e\"4XDx\",\n :pwd3=\u003e\"4XDx\",\n :name=\u003e\"bU\",\n :age=\u003e 5,\n :euros=\u003e -452.311,\n :created=\u003e \"2019-06-20T11:40:34.547\",\n :customer=\u003e true,\n :draws=\u003e\n  [{:drawId=\u003e\"\", :drawName=\u003e\"P03AgdMqV\", :type=\u003e\"Dail\", :owner=\u003e\"dYzLRMCnVc\"},\n   {:drawId=\u003e\"\", :drawName=\u003e\"qw\", :type=\u003e\"Dail\", :owner=\u003e\"zkHhTEzM\"}],\n :zip=\u003e\"7168\",\n :address=\u003e\"21 Doom Av\",\n :city=\u003e\"Rom\",\n :wagers=\u003e[\"34AAB\", \"dfffDD\", \"33499A\"],\n :country=\u003e\"Spai\",\n :mobilePhone=\u003e\"(237)17640431\",\n :sex=\u003e\"mal\",\n :display=\u003etrue,\n :user_names=\u003e[\"FF\"]\n }\n```\n\n### Return the select_fields or the pattern_fields\n\nIf you need a list of select fields or pattern fields that exist on your hash you can use the methods: select_fields and pattern_fields\n\nIt will return an array with all the fields found. On every entry of the array you will see keys to the field.\n\n```ruby\nall_select_fields = my_hash.select_fields\nselect_fields_on_correct = my_hash.select_fields(:correct)\n\nall_pattern_fields = my_hash.pattern_fields\npattern_fields_on_correct = my_hash.pattern_fields(:correct)\n```\n\nall_select_fields contains: \n\n```ruby\n[[:draws, 0, :type],\n [:draws, 1, :type],\n [:city, :correct],\n [:country, :correct],\n [:sex]]\n```\n\nselect_fields_on_correct contains: \n\n```ruby\n[[:draws, 0, :type], \n [:draws, 1, :type], \n [:city], \n [:country], \n [:sex]]\n```\n\nall_pattern_fields contains: \n\n```ruby\n[[:loginame],\n [[:pwd1, :pwd2, :pwd3]],\n [:name],\n [:draws, 0, :drawId],\n [:draws, 0, :drawName],\n [:draws, 0, :owner, :correct],\n [:draws, 1, :drawId],\n [:draws, 1, :drawName],\n [:draws, 1, :owner, :correct],\n [:zip, :correct],\n [:mobilePhone, :correct]],\n [:user_names]\n```\n\npattern_fields_on_correct contains: \n\n```ruby\n[[:loginame],\n [[:pwd1, :pwd2, :pwd3]],\n [:name],\n [:draws, 0, :drawId],\n [:draws, 0, :drawName],\n [:draws, 0, :owner],\n [:draws, 1, :drawId],\n [:draws, 1, :drawName],\n [:draws, 1, :owner],\n [:zip],\n [:mobilePhone]],\n [:user_names]\n```\n\n\n### dig and bury Hash methods\nIn case you want to access the values on a hash structure by using the key array location, you can use the 'dig' method on the Hash class:\n\n```ruby\nmin_length_error = my_hash.generate :correct, errors: :min_length\n\npatterns = my_hash.pattern_fields :correct\n\npatterns.each{|key|\n  if key[0].kind_of?(Array) # same values, like in pwd1, pwd2 and pwd3\n    puts \"#{key} same values\"\n    value = min_length_error.dig(key[0][0])\n  else\n    value = min_length_error.dig(*key)\n  end\n  \n  pattern = my_hash.select_key(:correct).dig(*key)\n  puts \"the value: '#{value}' was generated from the key: #{key} with pattern: #{pattern}\"\n}\n```\n\nThis returns something like: \n\n```\nthe value: '5z' was generated from the key: [:loginame] with pattern: 5-10:/xn/\n[[:pwd1, :pwd2, :pwd3]] same values\nthe value: '5' was generated from the key: [[:pwd1, :pwd2, :pwd3]] with pattern: 5-10:L/n/\nthe value: 'KshiYAmp' was generated from the key: [:name] with pattern: 10-20:T_/x/\nthe value: '722' was generated from the key: [:draws, 0, :drawId] with pattern: 5:N\nthe value: '4' was generated from the key: [:draws, 0, :drawName] with pattern: 10:Ln\nthe value: 'jhVZkII' was generated from the key: [:draws, 0, :owner] with pattern: 20:L\nthe value: '260' was generated from the key: [:draws, 1, :drawId] with pattern: 5:N\nthe value: 'ssty8hlnJ' was generated from the key: [:draws, 1, :drawName] with pattern: 10:Ln\nthe value: 'zPvcwOyyXvWSgNHsuv' was generated from the key: [:draws, 1, :owner] with pattern: 20:L\nthe value: '242' was generated from the key: [:zip] with pattern: 5:N\nthe value: '(91)7606' was generated from the key: [:mobilePhone] with pattern: [\"(\", :\"3:N\", \")\", :\"6-8:N\"]\n```\n\nRuby Hash class doesn't have a method to allocate a value using the key array location so we added to Hash class a method for that purpose, the 'bury' method.\n\n```ruby\ndefault_values = my_hash.generate :default\n\ndefault_values.bury([:draws, 0, :drawName], \"FirstDraw\")\n```\n\nAfter using the bury method default_values will contain:\n\n```ruby\n{:loginame=\u003e\"i0v2jy\",\n :pwd1=\u003e\"x33exx\",\n :pwd2=\u003e\"x33exx\",\n :pwd3=\u003e\"x33exx\",\n :name=\u003e\"HdmsjLxlEgYIFY\",\n :age=\u003e 20,\n :euros=\u003e 155.11,\n :created=\u003e\"2019-06-20T11:40:34.547Z\",\n :customer=\u003e false,\n :draws=\u003e\n  [{:drawId=\u003e\"12318\",\n    :drawName=\u003e\"FirstDraw\",\n    :type=\u003e\"Weekely\",\n    :owner=\u003e\"admin\"},\n   {:drawId=\u003e\"18947\",\n    :drawName=\u003e\"LPgf2ZQvkG\",\n    :type=\u003e\"Weekely\",\n    :owner=\u003e\"admin\"}],\n :zip=\u003e\"00000\",\n :address=\u003e\"21 Doom Av\",\n :city=\u003e\"Madrid\",\n :wagers=\u003e[\"34AAB\", \"dfffDD\", \"33499A\"],\n :country=\u003e\"Spain\",\n :mobilePhone=\u003e\"(987)654321\",\n :sex=\u003e\"male\",\n :display=\u003etrue,\n :user_names=\u003e[\"FFrriNdw\", \"ACc\"]\n }\n```\n\n### Validating hashes\n\nIf you have a Hash that should follow the patterns you specified (in this example declared on my_hash) and you want to validate, then use the 'validate' method.\n\nThis is specially useful to test REST APIs responses in JSON\n\nIf we have a hash with these values:\n\n```ruby\nvalues = { \n :loginame=\u003e\"rdewvqur\",\n :pwd1=\u003e\"d3ulo\",\n :pwd2=\u003e\"d3ulo\",\n :pwd3=\u003e\"d3ulo\",\n :name=\u003e\"LTqVKxxFCTqpkdjFkxU\",\n :age=\u003e 20,\n :euros=\u003e 155.11,\n :created=\u003e\"2019-06-20T11:40:34.547Z\",\n :customer=\u003e false,\n :draws=\u003e\n  [{:drawId=\u003e\"54a43\",\n    :drawName=\u003e\"h3F24yjMWp\",\n    :type=\u003e\"Daily\",\n    :owner=\u003e\"abIZMRxTDsWjQcpdspZt\"},\n   {:drawId=\u003e\"13010\",\n    :drawName=\u003e\"NurCEAtE1M\",\n    :type=\u003e\"Daily\",\n    :owner=\u003e\"vSVoqtSzHkbvRNyJoYGz\"}],\n :zip=\u003e\"30222\",\n :address=\u003e\"21 Doom Av\",\n :city=\u003e\"New York\",\n :wagers=\u003e[\"34AAB\", \"dfffDD\", \"33499A\"],\n :country=\u003e\"Iceland\",\n :mobilePhone=\u003e\"(441)97037845\",\n :sex=\u003e\"male\",\n :display=\u003etrue,\n :user_names=\u003e['ddfdsa']\n }\n```\n\nTo validate those values against the patterns defined on my_hash:\n\n```ruby\nresults_all_fields = my_hash.validate :correct, values\n\nresults_pattern_fields = my_hash.validate_patterns :correct, values\n```\n\nresults_all_fields will contain all the validation errors:\n\n```ruby\n{:loginame=\u003e[:value, :required_data],\n :draws=\u003e[{:drawId=\u003e[:value, :string_set_not_allowed]}],\n :city=\u003efalse}\n```\n\nand results_pattern_fields will contain only the validation errors for the fields containing patterns:\n\n```ruby\n{:loginame=\u003e[:value, :required_data],\n :draws=\u003e[{:drawId=\u003e[:value, :string_set_not_allowed]}]}\n```\n\nThe possible validation values returned:\n\n    :length: wrong length, minimum or maximum\n    :min_length: wrong minimum length\n    :max_length: wrong maximum length\n    :value: wrong resultant value\n    :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.\n    :excluded_data: the resultant string will include one or more characters that should be excluded. It works only if excluded data supplied on the pattern.\n    :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.\n\nYou can also supply nested pattern keys for the patterns to be more specific: `{'draws.drawId': :\"4:N\"}`\n\n### Change only one value at a time and return an Array of Hashes\n\nLet's guess we need to test a typical registration REST service and the service has many fields with many validations but we want to test it one field at a time.\n\nThen the best thing you can do is to use the method NiceHash.change_one_by_one.\n\n\n```ruby\n\nwrong_min_length_hash = my_hash.generate(:correct, errors: :min_length)\n\narray_of_hashes = NiceHash.change_one_by_one([my_hash, :correct], wrong_min_length_hash)\n\narray_of_hashes.each {|hash_with_one_wrong_field|\n  #Here your code to send through http the JSON data stored in hash_with_one_wrong_field\n  \n  #if you want to know which field is the one that is wrong:\n  res = my_hash.validate(:correct, hash_with_one_wrong_field)\n}\n```\n\nTake a look at a full example: https://gist.github.com/MarioRuiz/824d7a462b62fd85f02c1a09455deefb\n\n### Adding other values on run time when calling `generate` method\n\nIf you need a value to be supplied for your key on run time every time you call the `generate` method you can use `lambda`\n\n```ruby\n    my_hash = {\n        loginname: :\"10:Ln\",\n        datetime: lambda {\n            Time.now.stamp\n        },\n        other: Time.now.stamp\n    }\n\n    pp my_hash.gen\n    sleep 0.3\n    pp my_hash.gen\n\n```\n\nAS you can see in this example the value of the field `datetime` is different every time we generate the hash, but the value of the field `other` is generated the first time and it doesn't change later.\n\nThis is the output:\n\n```\n{:loginname=\u003e\"dQ1gwPvHHZ\",\n :datetime=\u003e\"2019-01-02T13:41:05.536\",\n :other=\u003e\"2019-01-02T13:41:05.536\"}\n\n{:loginname=\u003e\"WUCnWJmm0o\",\n :datetime=\u003e\"2019-01-02T13:41:05.836\",\n :other=\u003e\"2019-01-02T13:41:05.536\"}\n```\n\n#### Accessing other values of the hash on run time\n\nIf you need for example to access another value of the key to generate a value on run time you can use `NiceHash.values`\n\nTake a look at this example:\n\n```ruby\n\nmy_hash = {\n    loginname: :\"10:Ln\",\n    send_email: :\"true|false\",\n    email: lambda {\n        if NiceHash.values._send_email=='true'\n            :\"30-50:@\".gen\n        else\n            \"\"\n        end\n    }\n}\n\npp my_hash.gen\npp my_hash.gen\npp my_hash.gen\n\n```\n\nThis code will generate a hash where `send_email` can be `true` or `false`. In case it is `true` it will generate a value for the key `email` from 30 to 50 characters valid email, in case it is `false` it will contain empty string.\n\nThis is a possible output of the previous code:\n\n```ruby\n{:loginname=\u003e\"jnazA9iGN3\",\n :send_email=\u003e\"true\",\n :email=\u003e\"aRR4SsPaA.0ilh_RW0_y.sQL@goxrssgtkp4df.nkc\"}\n\n{:loginname=\u003e\"2CjT9wLMxq\", :send_email=\u003e\"false\", :email=\u003e\"\"}\n\n{:loginname=\u003e\"XlMpgNPlLR\", :send_email=\u003e\"false\", :email=\u003e\"\"}\n```\n\n### Compare the structure of a replica with the supplied structure\n\nBy using the NiceHash.compare_structure method you can analyze the supplied replica and verify that the structure follows the one supplied on structure. It supports nested combination of arrays and hashes. It will return true if the comparison is successful.\n\n```ruby\n      require 'nice_hash'\n\n      my_structure = [\n        {  name: 'xxx',\n           zip: 'yyyy',\n           customer: true,\n           product_ids: [1]\n        }\n      ]\n      my_replica = [ {name: 'Peter Ben', zip: '1121A', customer: false, product_ids: []},\n                     {name: 'John Woop', zip: '74014', customer: true, product_ids: [10,120,301]}]\n\n      NiceHash.compare_structure(my_structure, my_replica)\n      #\u003etrue\n```\n\nAnother example that will return false since customer key is missing on first value in replica and the product_ids in the second value of replica contains an string instead of an integer.\n\n```ruby\n      my_structure = [\n        {  name: 'xxx',\n           zip: 'yyyy',\n           customer: true,\n           product_ids: [1]\n        }\n      ]\n      my_replica = [ {name: 'Peter Ben', zip: '1121A', product_ids: []},\n                     {name: 'John Woop', zip: '74014', customer: true, product_ids: [10,'120',301]}]\n\n      NiceHash.compare_structure(my_structure, my_replica)\n      #\u003efalse\n```\n\nAlso you can use a third parameter, compare_only_if_exist_key (Boolean), by default false. If true, in case an element exist on structure but doesn't exist on replica won't be verified.\n\n\n\nThe last parameter (patterns) allow you to add verification of data values following the patterns supplied on a one level hash.\n\nValid patterns:\n- a regular expression\n- any string_pattern, more info: string_pattern project: https://github.com/MarioRuiz/string_pattern\n- array of a string_pattern: \n  - [ :'10-20:L' ]\n- Boolean: specifying Boolean will check if the value is TrueClass or FalseClass\n- ranges: Any kind of numeric ranges, for example: \n  - 10..400\n  - -20..50\n  - 60.0..500.0\n  - 10.. (from 10 to infinite) Only from Ruby 2.6\n- DateTime: it will verify if the value is following Time stamp string '2019-06-20T12:01:09.971Z' or if the object is a Time, Date or DateTime class\n- selectors, one of the values. Example: \"uno|dos|tres\"\n\n### Other useful methods\n\n#### Time stamp\nIn case you need the time stamp, we added the method `stamp` to the `Time` class\n\n```ruby\n    puts Time.now.stamp\n    #\u003e 2019-01-02T11:03:23.620Z\n```\n\n#### Random dates\nIn class `Date` we added a very handy `random` method you can use to generate random dates.\n\n```ruby\n    # random date from today to 60 days after\n    puts Date.today.random(60)\n    \n    # random date from 01-09-2005 to 100 days later\n    puts Date.strptime('01-09-2005', '%d-%m-%Y').random(100)\n\n    # random date from 2003/10/31 to today\n    puts Date.new(2003,10,31).random(Date.today) \n```\n\n#### Deep copy of a hash\nIf you need a clean copy of a hash use the method `deep_copy`\n\n```ruby\nmy_hash = {one: 1, two: 2, three: {car: 'seat'}}\n\nmy_new_hash = my_hash.deep_copy # using deep_copy method\nmy_new_hash[:three][:car] = 'changed'\nmy_new_hash[:two] = 'changed'\np my_hash\n# my_hash doesn't change\n#\u003e{:one=\u003e1, :two=\u003e2, :three=\u003e{:car=\u003e\"seat\"}}\n\nmy_new_hash = my_hash.clone # using clone or dup or direct assignment\nmy_new_hash[:three][:car] = 'changed'\nmy_new_hash[:two] = 'changed'\np my_hash\n# my_hash changed!\n#\u003e{:one=\u003e1, :two=\u003e2, :three=\u003e{:car=\u003e\"changed\"}}\n```\n\n#### Nested deletion\nIf you want to delete a key on a nested hash you can use `delete_nested` and supply the key you want:\n\n```ruby\n  my_hash = { user: {\n                      address: {\n                             city: 'Madrid',\n                             country: 'Spain'\n                          },\n                      name: 'Peter',\n                      age: 33\n                    },\n              customer: true\n  }\n    NiceHash.delete_nested(my_hash, 'user.address.city')\n    #\u003e{:user=\u003e{:address=\u003e{:country=\u003e\"Spain\"}, :name=\u003e\"Peter\", :age=\u003e33}, :customer=\u003etrue}\n\n```\n#### Deep merge of two hashes\nIf you need to merge multidimensional hashes\n\n```ruby\nmy_hash = {one: 1, two: 2, three: {car: 'seat'}}\nother_hash = {one: 11, four: 44, three: {car: 'ferrari', model: 'unknown'}}\np my_hash.nice_merge(other_hash)\n#\u003e{:one=\u003e11, :two=\u003e2, :three=\u003e{:car=\u003e\"ferrari\", :model=\u003e\"unknown\"}, :four=\u003e44}\n```\n\n\n#### Boolean class\nWe added the possibility to check if a value is boolean or not since in Ruby doesn't exist, just TrueClass and FalseClass\n\n```ruby\nvalue = true\ntext = 'true'\n\nvalue.is_a?(Boolean) #\u003e true\ntext.is_a?(Boolean) #\u003e false\n\n```\n\n#### in?(array)\nAdded method in? to all objects that accepts array as a parameter.\n\n```ruby\n'uno'.in?(['uno','dos']) #\u003e true\n:uno.in? [:uno, :dos] #\u003e true\n5.in? [1,2,3,4,6] #\u003e false\n\n```\n\n### Other tools integration\n\n#### Tabulo\n\nYou can use tabulo (https://github.com/matt-harvey/tabulo) and nice_hash together:\n\n```ruby\nrequire 'nice_hash'\nrequire 'tabulo'\n\nmy_data = [\n  {id:'1', name: 'Peter', city: 'London', account: '112124', client: true },\n  {id:'2', name: 'Ann', city: 'Madrid', account: '4454656', client: true },\n  {id:'3', name: 'John', city: 'New York', account: '5645666', client: false }\n]\n\nputs Tabulo::Table.new(my_data, :id, :name, :city, :client, border: :modern).pack\n```\n\nIt will generate:\n```\n┌────┬───────┬──────────┬────────┐\n│ id │  name │   city   │ client │\n├────┼───────┼──────────┼────────┤\n│ 1  │ Peter │ London   │  true  │\n│ 2  │ Ann   │ Madrid   │  true  │\n│ 3  │ John  │ New York │  false │\n└────┴───────┴──────────┴────────┘\n```\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/marioruiz/nice_hash.\n\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarioruiz%2Fnice_hash","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarioruiz%2Fnice_hash","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarioruiz%2Fnice_hash/lists"}