{"id":13879722,"url":"https://github.com/exAspArk/include_module","last_synced_at":"2025-07-16T15:32:57.240Z","repository":{"id":56877527,"uuid":"64509016","full_name":"exAspArk/include_module","owner":"exAspArk","description":"Include modules explicitly! :point_up:","archived":false,"fork":false,"pushed_at":"2016-10-03T13:15:37.000Z","size":17,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-08T05:20:09.383Z","etag":null,"topics":["mixins","modules","ruby"],"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/exAspArk.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-07-29T20:36:44.000Z","updated_at":"2019-09-24T15:48:34.000Z","dependencies_parsed_at":"2022-08-20T11:31:06.275Z","dependency_job_id":null,"html_url":"https://github.com/exAspArk/include_module","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/exAspArk/include_module","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exAspArk%2Finclude_module","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exAspArk%2Finclude_module/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exAspArk%2Finclude_module/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exAspArk%2Finclude_module/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/exAspArk","download_url":"https://codeload.github.com/exAspArk/include_module/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exAspArk%2Finclude_module/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265521500,"owners_count":23781522,"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":["mixins","modules","ruby"],"created_at":"2024-08-06T08:02:30.296Z","updated_at":"2025-07-16T15:32:57.008Z","avatar_url":"https://github.com/exAspArk.png","language":"Ruby","readme":"# include_module\n\n[![Build Status](https://travis-ci.org/exAspArk/include_module.svg)](https://travis-ci.org/exAspArk/include_module)\n[![codecov](https://codecov.io/gh/exAspArk/include_module/branch/master/graph/badge.svg)](https://codecov.io/gh/exAspArk/include_module)\n[![Code Climate](https://codeclimate.com/github/exAspArk/include_module/badges/gpa.svg)](https://codeclimate.com/github/exAspArk/include_module)\n\nThere are some general problems with mixins, and a lot of people complain about\nthem:\n\n* [7 Patterns to Refactor Fat ActiveRecord Models](http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/) (Ruby)\n\u003e  Using mixins like this is akin to “cleaning” a messy room by dumping the\n\u003e  clutter into six separate junk drawers and slamming them shut. Sure, it looks\n\u003e  cleaner at the surface, but the junk drawers actually make it harder to\n\u003e  identify and\n\u003e  implement the decompositions and extractions necessary to clarify the domain\n\u003e  model.\n\n* [Mixins considered harmful/1](http://www.artima.com/weblogs/viewpost.jsp?thread=246341) (Python)\n\u003e Injecting methods into a class namespace is a bad idea for a very simple\n\u003e reason: every time you use a mixin, you are actually polluting your class\n\u003e namespace and losing track of the origin of your methods.\n\n* [Mixins Considered Harmful](https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html) (JavaScript)\n\u003e * Mixins introduce implicit dependencies\n\u003e * Mixins cause name clashes\n\u003e * Mixins cause snowballing complexity\n\nThe **include_module** gem was created to help you to use mixing (aka `module` in Ruby)\nexplicitly.\nIt is a simple library with just 90 LOC, with\nzero dependencies, without any monkey patches and method overridings.\n\n## Usage\n\nThere are 2 common ways to use mixins in Ruby.\n\n1) [Module.included(base)](http://ruby-doc.org/core-2.3.1/Module.html#method-i-included)\n\n```ruby\nmodule UserMixin\n  def self.included(base)\n    base.extend(ClassMethods)\n    base.class_eval do\n      belongs_to :account\n    end\n  end\n\n  module ClassMethods\n    def top_user\n      User.order(rating: :desc).first\n    end\n  end\n\n  def name\n    \"#{first_name} #{last_name}\"\n  end\nend\n\nclass User\n  include UserMixin\nend\n```\n\nThis is a standard way of using mixins in Ruby. The problem here is that when\nyou look at the `User` you have no idea which methods the `UserMixin`\ndefines in the class.\n\n2) [ActiveSupport::Concern](http://api.rubyonrails.org/classes/ActiveSupport/Concern.html)\n\n```ruby\nmodule UserMixin\n  extend ActiveSupport::Concern\n\n  included do\n    belongs_to :account\n  end\n\n  class_methods do\n    def top_user\n      User.order(rating: :desc).first\n    end\n  end\n\n  def name\n    \"#{first_name} #{last_name}\"\n  end\nend\n\nclass User\n  include UserMixin\nend\n```\n\nBy extending your module, you add `.class_methods` which basically hides\n`ClassMethods` module inside, overrides `.append_features` and `.included` methods.\nAdditionally it keeps tracking how many times `.included`\nwas called to raise a custom exception about multiple \"included\" blocks.\n\nBut mostly `ActiveSupport::Concern` has the same problem as standard `Module.included`.\nWhy can't we define explicitly which methods we would like to use from a mixin?\n\n### **include_module**\n\n```ruby\nmodule UserMixin\n  module ClassMethods\n    def top_user\n      User.order(rating: :desc).first\n    end\n  end\n\n  INCLUDED = proc do\n    belongs_to :account\n  end\n\n  def name\n    \"#{first_name} #{last_name}\"\n  end\nend\n\nclass User\n  extend IncludeModule\n\n  extend_module UserMixin::ClassMethods, methods: [:top_user]\n  include_module UserMixin, included: true, methods: [:name]\nend\n```\n\nNow when you look at the class you can see which methods \"included_module\" adds in it.\nAnd it's all done without any monkey patches or method overridings.\n\nIt is almost in-place replacement for `ActiveSupport::Concern`. Here is a diff:\n\n```ruby\n module UserMixin\n-  extend ActiveSupport::Concern\n-\n-  included do\n+  INCLUDED = proc do\n     belongs_to :account\n   end\n\n ...\n\n class User\n+  extend IncludeModule\n+\n-  include_module UserMixin\n+  extend_module UserMixin::ClassMethods, methods: [:top_user]\n+  include_module UserMixin, included: true, methods: [:name]\n end\n```\n\nYou can also control which methods you would like to include, rename them\nwhile including in order to avoid name clashes, etc. Please see more examples below.\n\n## How Does It Work?\n\n* Include no methods\n\nWhen you add `extend IncludeModule`, you add just 2 public methods called `include_module` and `extend_module` in\nyour class.\n\n```ruby\nclass User\n  extend IncludeModule\n  include_module UserMixin\nend\n```\n\nBy default when you call `include_module` without any options, it won't load anything.\n\n* Include all methods\n\nIf you want to include everything from your module, you can pass the following options:\n\n```ruby\nclass User\n  extend IncludeModule\n  include_module UserMixin, included: true, methods: :all\nend\n```\n\nIt will `include` you module, `extend` your `ClassMethods` and `class_eval` your\n`INCLUDED` proc without any changes.\n\n* Include some methods\n\nYou can define explicitly which methods you want to include from you module:\n\n```ruby\nmodule TestModule\n  def foo\n    :foo\n  end\n\n  def bar\n    :bar\n  end\nend\n\nclass TestClass\n  extend IncludeModule\n  include_module TestModule, methods: [:foo]\nend\n```\n\nIn this case we have only `TestClass#foo` method implemented.\nIt basically creates a new anonymous module which contains only specified methods and includes it as usual.\n\n* Rename included method\n\n```ruby\nclass User\n  extend IncludeModule\n  include_module UserMixin, methods: [name: :full_name]\nend\n```\n\nWe can rename methods while including a mixin by creating a new anonymous module as in the previous example.\nSo `User#full_name` method will be available instead of `User#name`.\n\n## Installation\n\nInstall Ruby version \u003e= 2.1.\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'include_module'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install include_module\n\n## Development\n\nInstall development dependencies:\n\n    gem install bundler\n    bundle install\n\nRun tests:\n\n    make test\n\nTo release a new version, update the version number in `include_module.gemspec`,\nand then run:\n\n    make release\n\nWhich will create a git tag for the version, push git commits and tags, and push\nthe `.gem` file to [rubygems.org](https://rubygems.org).\n\n## What's New?\n\nPlease read the [changelog](./CHANGELOG.md).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at\nhttps://github.com/exAspArk/include_module.\n\nTo open a pull request:\n\n1. [Fork it](https://github.com/exAspArk/include_module/fork)\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create [a new Pull\nRequest](https://github.com/exAspArk/include_module/compare)\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FexAspArk%2Finclude_module","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FexAspArk%2Finclude_module","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FexAspArk%2Finclude_module/lists"}