{"id":15405681,"url":"https://github.com/zverok/procme","last_synced_at":"2025-04-17T01:52:46.255Z","repository":{"id":31975068,"uuid":"35545224","full_name":"zverok/procme","owner":"zverok","description":"Fun with proc","archived":false,"fork":false,"pushed_at":"2020-05-05T08:52:23.000Z","size":12,"stargazers_count":17,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-29T05:51:16.959Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/zverok.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-13T11:28:46.000Z","updated_at":"2022-01-10T12:39:20.000Z","dependencies_parsed_at":"2022-08-20T16:00:45.032Z","dependency_job_id":null,"html_url":"https://github.com/zverok/procme","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zverok%2Fprocme","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zverok%2Fprocme/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zverok%2Fprocme/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zverok%2Fprocme/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zverok","download_url":"https://codeload.github.com/zverok/procme/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248631688,"owners_count":21136562,"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":[],"created_at":"2024-10-01T16:18:10.369Z","updated_at":"2025-04-17T01:52:46.237Z","avatar_url":"https://github.com/zverok.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ProcMe\n\n[![Gem Version](https://badge.fury.io/rb/procme.svg)](http://badge.fury.io/rb/procme)\n\n## Install\nWith Bundler:\n\n```ruby\ngem 'procme'\n```\n\nin your Gemfile, then `bundle install`.\n\nOr without:\n```\ngem install procme\n```\n\n[YARD docs](http://www.rubydoc.info/gems/procme)\n\n## Usage\n\n```ruby\n# Given you have\nclass Person \u003c Struct.new(:name, :age, :gender)\n  def greet(who)\n    \"#{name}: Hello, #{who}!\"\n  end\n\n  def greet!(who)\n    puts greet(name)\n  end\n\n  def inspect\n    \"#\u003c#{name}, #{gender}, #{age}\u003e\"\n  end\nend\n\npeople = [\n  Person.new('John', 30, 'male'),\n  Person.new('Jane', 23, 'female'),\n  Person.new('Jake', 48, 'male'),\n  Person.new('Judith', 16, 'female')\n]\n\n# With ProcMe you can:\ninclude ProcMe\n\n# ProcMe::fltr(method: match) - filter by attribute values/method calls:\np people.select(\u0026fltr(gender: 'female', age: 18...30))\n# =\u003e [#\u003cJane, female, 23\u003e]\n\n# ProcMe::get(:method1, :method2) - bulk get attributes\np people.map(\u0026get(:gender, :age))\n# =\u003e [[\"male\", 30], [\"female\", 23], [\"male\", 48], [\"female\", 16]]\n\n# ...which is really useful when sorting:\np people.sort_by(\u0026get(:gender, :age))\n# =\u003e [#\u003cJudith, female, 16\u003e, #\u003cJane, female, 23\u003e, #\u003cJohn, male, 30\u003e, #\u003cJake, male, 48\u003e]\n\n# ProcMe::set(attr: value) - bulk set value:\np people.map(\u0026set(gender: 'female'))\n# =\u003e [#\u003cJohn, female, 30\u003e, #\u003cJane, female, 23\u003e, #\u003cJake, female, 48\u003e, #\u003cJudith, female, 16\u003e]\n\n# ProcMe::call(method: args) - bulk call method with arguments:\npeople.each(\u0026call(greet!: 'Ellis'))\n# Output:\n#   John: Hello, Ellis!\n#   Jane: Hello, Ellis!\n#   Jake: Hello, Ellis!\n#   Judith: Hello, Ellis!\n\n# also works with #map:\npeople.map(\u0026call(greet: 'Ellis'))\n# =\u003e [\"John: Hello, Ellis!\", \"Jane: Hello, Ellis!\", \"Jake: Hello, Ellis!\", \"Judith: Hello, Ellis!\"]\n\n# ...and with several arguments:\np people.map(\u0026:name).map(\u0026call(sub: ['J', 'F']))\n# =\u003e [\"Fohn\", \"Fane\", \"Fake\", \"Fudith\"]\n\n# ...and even several method you can call!\np people.map(\u0026:name).map(\u0026call(:downcase, :'+' =\u003e ', hello'))\n# =\u003e [[\"john\", \"John, hello\"], [\"jane\", \"Jane, hello\"], [\"jake\", \"Jake, hello\"], [\"judith\", \"Judith, hello\"]]\n# Note that each method call is performed on ORIGINAL object\n```\n\n## Rationale\n\nLook at symple example\n\n```ruby\npeople.select{|p| p.gender == 'female'}\npeople.select(\u0026fltr(gender: 'female'))\n```\n\nAt a first glance, there's not a very big difference,\neven in symbols count (ok, ProcMe version 1 symbol shorter :)\n\nYet there's one important difference: ProcMe version is\n[DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself). It's not\nDRY for the sake of DRY, it's for better, cleaner and error-prone code.\n\nAssume you are copying the code while rewriting it:\n\n```ruby\naliens.select{|a| p.gender == 'female'}\n#                 ^ bang! It was not DRY enough!\n\n# With ProcMe\naliens.select(\u0026fltr(gender: 'female'))\n# just no repeating - no place for errors\n```\n\nIn fact, the rationale it the same, as it was for inventing `Symbol#to_proc`.\n\nProcMe is very small and simple, without any monkey-patching of core classes.\nOnly four methods (`fltr`, `get`, `set`, `call`), which you can include\nin any namespace or use without inclusion, for ex:\n\n```ruby\nP = ProcMe # to be short\n\npeople.select(\u0026P.fltr(gender: 'female'))\n```\n\n## Should you use it?\n\nFrankly, I don't know. Things that mimic core language features can be\nextremely useful, yet potentially they make your code more obscure for\nreader. Though I think that ProcMe's syntax is pretty self-explanatory,\nyou colleagues may have other opinion.\n\nAs for me, since invention of this little thingy I've found it extremely\nhandy and useful.\n\n## Small gotchas\n\n`ProcMe.fltr` uses `#===` while comparing values. This way you can filter\nstrings by regular expressions or numbers by ranges. One counterintuitive\nthings is going on when you try to filter by object class:\n\n```ruby\n['test', 'me'].select(\u0026fltr(class: String)) # =\u003e []\n```\n\nIt's because you should check object itself, not its class, to match with\n`===`. The solution is simple:\n\n```ruby\n['test', 'me'].select(\u0026fltr(itself: String)) # =\u003e ['test', 'me']\n```\n\n`#itself` method is available in Ruby \u003e= 2.2, and easily backported to\nearlier versions.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzverok%2Fprocme","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzverok%2Fprocme","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzverok%2Fprocme/lists"}