Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
fce594c
just a little detail: missing end
5v3n Nov 27, 2013
48c7665
Merge pull request #2 from 5v3n/master
kraatob Nov 27, 2013
c727006
Modularity 2 syntax
triskweline Jan 8, 2014
0e4d721
Add tests to ensure that including a traited module appends methods o…
triskweline Jan 8, 2014
8e0faf5
test to assert that multiple traits can be applied
triskweline Jan 8, 2014
55eadcd
migration script modularity1 => 2
triskweline Jan 8, 2014
2235469
Bump version, rewrite README in markdown and for version 2, fix migra…
triskweline Jan 8, 2014
5ae0dc9
Document migration script
triskweline Jan 8, 2014
68c2590
Merge branch 'modularity2'
triskweline Jan 8, 2014
e9df53c
fix README
triskweline Jan 8, 2014
cb6ab21
Update README.md
triskweline Jan 9, 2014
971873f
Update README.md
triskweline Jan 13, 2014
df8ee3b
fix migration script to read filenames from STDIN
kraatob Feb 4, 2014
7e3ccaf
add license to gemspec
stemps Nov 9, 2014
4883fe9
Merge pull request #3 from stemps/master
triskweline Nov 10, 2014
91cc0d6
Add a CHANGELOG
denzelem Aug 7, 2018
d93f236
Update the changelog to format https://makandracards.com/makandra/542…
denzelem Aug 23, 2018
efa8809
Remove migration code for upgrading to version 2
denzelem Aug 24, 2021
f28357a
Upgrade to RSpec 3
denzelem Aug 24, 2021
f377908
Update rubygems config and github defaults
denzelem Aug 24, 2021
452b76a
Add gemika and Github actions for testing
denzelem Aug 24, 2021
be12d70
Bump version from 2.0.1 to 3.0.0
denzelem Aug 24, 2021
3c19c84
Remove version from title
denzelem Aug 24, 2021
20373fc
Activate rubygems MFA
nhasselmeyer Feb 10, 2022
9884577
Merge pull request #8 from niklas-hasselmeyer/nh/activate-mfa
kratob Feb 10, 2022
17b7253
Bump version from 3.0.0 to 3.0.1
brunosedler Mar 9, 2022
cf62df6
Add support for separation of positional and keyword arguments in ruby 3
brunosedler May 20, 2022
8fe03e0
Bump version from 3.0.1 to 3.1.0
brunosedler Jun 1, 2022
2bfdf44
Update README.md
triskweline Oct 5, 2022
f3e8972
Add support for Ruby 3.2
brunosedler Feb 22, 2023
9d08cf3
Bump version from 3.1.0 to 3.2.0
brunosedler Mar 1, 2023
5fa550c
Add support for Ruby 3.3
tecden Dec 6, 2024
04b4abf
Add support for Ruby 3.4
tecden Feb 14, 2025
7117cba
Update Github Actions runner image
codener May 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
name: Tests
'on':
push:
branches:
- master
pull_request:
branches:
- master
jobs:
test:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
include:
- ruby: 2.5.7
gemfile: Gemfile
- ruby: 2.6.10
gemfile: Gemfile
- ruby: 2.7.4
gemfile: Gemfile
- ruby: 3.0.2
gemfile: Gemfile
- ruby: 3.1.2
gemfile: Gemfile
- ruby: 3.2.1
gemfile: Gemfile
- ruby: 3.3.6
gemfile: Gemfile
- ruby: 3.4.1
gemfile: Gemfile
env:
BUNDLE_GEMFILE: "${{ matrix.gemfile }}"
steps:
- uses: actions/checkout@v2
- name: Install ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: "${{ matrix.ruby }}"
- name: Bundle
run: |
gem install bundler:2.3.27
bundle install --no-deployment
- name: Run tests
run: bundle exec rspec
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@ doc
pkg
*.gem
.idea
Gemfile.lock
1 change: 1 addition & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--require spec_helper
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.5.7
45 changes: 45 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Changelog
All notable changes to this project will be documented in this file.

This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## Unreleased

### Breaking changes

### Compatible changes

- Add support for Ruby 3.3
- Add support for Ruby 3.4

## 3.2.0 - 2023-03-01

### Compatible changes

- Add support for Ruby 3.2


## 3.1.0 - 2022-06-01

### Compatible changes

- Add support for separation of positional and keyword arguments in ruby 3


## 3.0.1 - 2022-03-09

### Compatible changes

- Activate Rubygems MFA


## 3.0.0 - 2021-08-24

### Breaking changes

- Removed migration guide for modularity version 1.
- Removed support for Ruby < `2.5.0`.

### Compatible changes

- Added this CHANGELOG file.
7 changes: 6 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
source "http://rubygems.org"
source 'http://rubygems.org'

gemspec

gem 'rake'
gem 'rspec'
gem 'pry-byebug'
gem 'gemika'
47 changes: 47 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
PATH
remote: .
specs:
modularity (3.2.0)

GEM
remote: http://rubygems.org/
specs:
byebug (11.1.3)
coderay (1.1.3)
diff-lcs (1.4.4)
gemika (0.8.1)
method_source (1.0.0)
pry (0.13.1)
coderay (~> 1.1)
method_source (~> 1.0)
pry-byebug (3.9.0)
byebug (~> 11.0)
pry (~> 0.13.0)
rake (13.0.6)
rspec (3.10.0)
rspec-core (~> 3.10.0)
rspec-expectations (~> 3.10.0)
rspec-mocks (~> 3.10.0)
rspec-core (3.10.1)
rspec-support (~> 3.10.0)
rspec-expectations (3.10.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0)
rspec-mocks (3.10.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0)
rspec-support (3.10.2)

PLATFORMS
ruby
x86_64-linux

DEPENDENCIES
gemika
modularity!
pry-byebug
rake
rspec

BUNDLED WITH
2.3.27
21 changes: 21 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2009 Henning Koch

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
20 changes: 0 additions & 20 deletions MIT-LICENSE

This file was deleted.

128 changes: 128 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
[![Tests](https://github.com/makandra/modularity/workflows/Tests/badge.svg)](https://github.com/makandra/modularity/actions)

# Modularity - Traits and partial classes for Ruby

Modularity enhances Ruby's [`Module`](http://apidock.com/ruby/Module) so it can be used traits and partial classes.
This allows very simple definition of meta-programming macros like the
`has_many` that you know from Rails.

Modularity also lets you organize large models into multiple source files
in a way that is less awkward than using modules.

## Installation

Add the following to your `Gemfile`:

```ruby
gem 'modularity'
```

Now run `bundle install`.

## Example 1: Easy meta-programming macros

Ruby allows you to construct classes using meta-programming macros like
`acts_as_tree` or `has_many :items`. These macros will add methods,
callbacks, etc. to the calling class. However, right now Ruby (and Rails) makes it awkward to define
such macros in your project as part of your application domain.

Modularity allows you to extract common behaviour into reusable macros by defining traits with parameters.
Your macros can live in your application, allowing you to express your application domain in both classes
and macros.

Here is an example of a `strip_field` macro, which created setter methods that remove leading and trailing whitespace from newly assigned values:

```ruby
# app/models/article.rb
class Article < ActiveRecord::Base
include DoesStripFields[:name, :brand]
end

# app/models/shared/does_strip_fields.rb
module DoesStripFields
as_trait do |*fields|
fields.each do |field|
define_method("#{field}=") do |value|
self[field] = value.strip
end
end
end
end
```

Notice the `as_trait` block.

We like to add `app/models/shared` and `app/controllers/shared` to the load paths of our Rails projects.
These are great places to store macros that are re-used from multiple classes.

## Example 2: Mixins with class methods

Using a module to add both instance methods and class methods is
[very awkward](http://redcorundum.blogspot.com/2006/06/mixing-in-class-methods.html).
Modularity does away with the clutter and lets you say this:

```ruby
# app/models/model.rb
class Model
include Mixin
end

# app/models/mixin.rb
module Mixin
as_trait do
def instance_method
# ...
end
def self.class_method
# ..
end
end
end
```

`private` and `protected` will also work as expected when defining a trait.

## Example 3: Splitting a model into multiple source files

Models are often concerned with multiple themes like "authentication", "contact info" or "permissions", each requiring
a couple of validations and callbacks here, and some method there. Modularity lets you organize your model into multiple
partial classes, so each file can deal with a single aspect of your model:

```ruby
# app/models/user.rb
class User < ActiveRecord::Base
include DoesAuthentication
include DoesPermissions
end

# app/models/user/does_authentication.rb
module User::DoesAuthentication
as_trait do
# methods, validations, etc. regarding usernames and passwords go here
end
end

# app/models/user/does_permissions.rb
module User::DoesPermissions
as_trait do
# methods, validations, etc. regarding contact information go here
end
end
```

Some criticism has been raised for splitting large models into files like this.
Essentially, even though have an easier time navigating your code, you will still
have one giant model with many side effects.

There are [many better ways](http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/)
to decompose a huge Ruby class.

## Development

* Install Bundler 2 `gem install bundler:2.2.22` and run `bundle install` to have a working development setup.
* Running tests for the current Ruby version: `bundle exec rake`
* Running tests for all supported Ruby version: Push the changes to Github in a feature branch, open a merge request and have a look at the test matrix in Github actions

## Credits

Henning Koch from [makandra.com](http://makandra.com/)
Loading