From fce594cbb88efc27a3fe2c70dc8c5a6f1a032847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20Kr=C3=A4uter?= Date: Wed, 27 Nov 2013 11:15:13 +0100 Subject: [PATCH 01/30] just a little detail: missing end --- README.rdoc | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rdoc b/README.rdoc index 3190ea7..2f385fe 100755 --- a/README.rdoc +++ b/README.rdoc @@ -58,6 +58,7 @@ Modularity does away with the clutter and lets you say this: def self.class_method # .. end + end end private and protected will also work as expected when defining a trait. From c72700673c7f312165b5c3545dd593d8adefec82 Mon Sep 17 00:00:00 2001 From: Henning Koch Date: Wed, 8 Jan 2014 13:53:06 +0100 Subject: [PATCH 02/30] Modularity 2 syntax --- lib/modularity.rb | 3 +- lib/modularity/as_trait.rb | 37 ++++++++++- lib/modularity/does.rb | 23 ------- lib/modularity/inflector.rb | 60 ------------------ modularity.gemspec | 1 + spec/as_trait_spec.rb | 121 +++++++++++++++++++++++++++++++----- spec/does_spec.rb | 93 --------------------------- spec/spec_helper.rb | 1 + 8 files changed, 141 insertions(+), 198 deletions(-) delete mode 100755 lib/modularity/does.rb delete mode 100755 lib/modularity/inflector.rb delete mode 100755 spec/does_spec.rb diff --git a/lib/modularity.rb b/lib/modularity.rb index 39e4ef5..402ce75 100755 --- a/lib/modularity.rb +++ b/lib/modularity.rb @@ -1,2 +1 @@ -require 'modularity/does' - +require 'modularity/as_trait' diff --git a/lib/modularity/as_trait.rb b/lib/modularity/as_trait.rb index f26ae95..f1145bd 100755 --- a/lib/modularity/as_trait.rb +++ b/lib/modularity/as_trait.rb @@ -1,9 +1,40 @@ module Modularity + + class ParametrizedTrait < Module + + def initialize(blank_trait, args) + @args = args + @macro = blank_trait.instance_variable_get(:@modularity_macro) + include(blank_trait) + end + + def included(base) + base.class_exec(*@args, &@macro) + end + + end + module AsTrait - def as_trait(&block) - @trait_macro = block + + def as_trait(¯o) + + @modularity_macro = macro + + def self.included(base) + unless base.is_a?(ParametrizedTrait) + base.class_exec(&@modularity_macro) + end + + end + + def self.[](*args) + blank_trait = self + ParametrizedTrait.new(blank_trait, args) + end + end + end end -Object.send :include, Modularity::AsTrait +Module.send(:include, Modularity::AsTrait) diff --git a/lib/modularity/does.rb b/lib/modularity/does.rb deleted file mode 100755 index c14b7c2..0000000 --- a/lib/modularity/does.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'modularity/inflector' -require 'modularity/as_trait' - -module Modularity - module Does - - def self.included(base) - base.extend ClassMethods - end - - module ClassMethods - def does(trait_name, *args) - trait_name = "#{Modularity::Inflector.camelize(trait_name.to_s)}Trait" - trait = Modularity::Inflector.constantize(trait_name) - macro = trait.instance_variable_get("@trait_macro") or raise "Missing trait directive in #{trait_name}" - class_exec(*args, ¯o) - end - end - - end -end - -Object.send :include, Modularity::Does diff --git a/lib/modularity/inflector.rb b/lib/modularity/inflector.rb deleted file mode 100755 index 5706eee..0000000 --- a/lib/modularity/inflector.rb +++ /dev/null @@ -1,60 +0,0 @@ -# These methods are backported from Rails so modularity works with plain Ruby. - -module Modularity - class Inflector - class << self - - # File activesupport/lib/active_support/inflector.rb, line 178 - def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true) - if first_letter_in_uppercase - lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } - else - lower_case_and_underscored_word.first.downcase + camelize(lower_case_and_underscored_word)[1..-1] - end - end - - - if Module.method(:const_get).arity == 1 - # Tries to find a constant with the name specified in the argument string: - # - # "Module".constantize # => Module - # "Test::Unit".constantize # => Test::Unit - # - # The name is assumed to be the one of a top-level constant, no matter whether - # it starts with "::" or not. No lexical context is taken into account: - # - # C = 'outside' - # module M - # C = 'inside' - # C # => 'inside' - # "C".constantize # => 'outside', same as ::C - # end - # - # NameError is raised when the name is not in CamelCase or the constant is - # unknown. - def constantize(camel_cased_word) - names = camel_cased_word.split('::') - names.shift if names.empty? || names.first.empty? - - constant = Object - names.each do |name| - constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name) - end - constant - end - else - def constantize(camel_cased_word) #:nodoc: - names = camel_cased_word.split('::') - names.shift if names.empty? || names.first.empty? - - constant = Object - names.each do |name| - constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name) - end - constant - end - end - - end - end -end diff --git a/modularity.gemspec b/modularity.gemspec index 89a9fd0..ac5015b 100755 --- a/modularity.gemspec +++ b/modularity.gemspec @@ -18,5 +18,6 @@ Gem::Specification.new do |s| s.add_development_dependency('rake') s.add_development_dependency('rspec', '<2') + s.add_development_dependency('rspec_candy') end diff --git a/spec/as_trait_spec.rb b/spec/as_trait_spec.rb index 48383ea..a47b67a 100755 --- a/spec/as_trait_spec.rb +++ b/spec/as_trait_spec.rb @@ -1,29 +1,116 @@ require 'spec_helper' -module Trait - as_trait do - "hi world" - end -end +describe Modularity::AsTrait do -module ParametrizedTrait - as_trait do |name| - "hi, #{name}" - end -end + describe '.included' do + + before :each do + @doing_class = Class.new + end -describe Modularity::AsTrait do + describe 'without parameters' do + + it "applies the trait macro of the given module" do + + module DoesSome + as_trait do + some_trait_included + end + end + + @doing_class.should_receive(:some_trait_included) + + @doing_class.class_eval do + include DoesSome + end + + end + + it "applies the trait macro of the given namespaced module" do + + module Some + module DoesChild + as_trait do + some_child_trait_included + end + end + end + + @doing_class.should_receive(:some_child_trait_included) + + @doing_class.class_eval do + include Some::DoesChild + end + + end - describe 'as_trait' do + it "lets a trait define methods with different visibility" do + + module DoesVisibility + as_trait do + def public_method_from_trait + end + protected + def protected_method_from_trait + end + private + def private_method_from_trait + end + end + end + + @doing_class.class_eval do + include DoesVisibility + end + + instance = @doing_class.new + + instance.public_methods.collect(&:to_s).should include("public_method_from_trait") + instance.protected_methods.collect(&:to_s).should include("protected_method_from_trait") + instance.private_methods.collect(&:to_s).should include("private_method_from_trait") + + end - it "should let modules save a proc upon loading" do - Trait.instance_variable_get("@trait_macro").call.should == "hi world" end - it "should let modules save a proc with parameters upon loading" do - ParametrizedTrait.instance_variable_get("@trait_macro").call("jean").should == "hi, jean" + describe "with parameters" do + + it "it applies a trait macro with parameters" do + + module DoesCallMethod + as_trait do |field| + send(field) + end + end + + @doing_class.should_receive(:foo) + @doing_class.class_eval do + include DoesCallMethod[:foo] + end + + end + + it "facilitates metaprogramming acrobatics" do + + module DoesDefineConstantMethod + as_trait do |name, return_value| + define_method name do + return_value + end + end + end + + @doing_class.class_eval do + include DoesDefineConstantMethod["some_method", "some_return_value"] + end + + instance = @doing_class.new + instance.should respond_to(:some_method) + instance.some_method.should == "some_return_value" + end + end end - + end diff --git a/spec/does_spec.rb b/spec/does_spec.rb deleted file mode 100755 index a918e86..0000000 --- a/spec/does_spec.rb +++ /dev/null @@ -1,93 +0,0 @@ -require 'spec_helper' - -module SomeTrait - as_trait do - some_trait_included - end -end - -module Some - module ChildTrait - as_trait do - some_child_trait_included - end - end -end - -module CallMethodTrait - as_trait do |field| - send(field) - end -end - -module VisibilityTrait - as_trait do - def public_method_from_trait - end - protected - def protected_method_from_trait - end - private - def private_method_from_trait - end - end -end - -module DefineConstantMethodTrait - as_trait do |name, return_value| - define_method name do - return_value - end - end -end - -class Doer -end - -describe Modularity::AsTrait do - - describe 'does' do - - it "should apply the named module" do - Doer.should_receive(:some_trait_included) - Doer.class_eval do - does "some" - end - end - - it "should apply a namespaced module, using slash-notation like require" do - Doer.should_receive(:some_child_trait_included) - Doer.class_eval do - does "some/child" - end - end - - it "should class_eval the as_trait proc on the doer" do - Doer.should_receive(:foo) - Doer.class_eval do - does "call_method", :foo - end - end - - it "should allow the trait to define methods with different visibility" do - Doer.class_eval do - does "visibility" - end - instance = Doer.new - instance.public_methods.collect(&:to_s).should include("public_method_from_trait") - instance.protected_methods.collect(&:to_s).should include("protected_method_from_trait") - instance.private_methods.collect(&:to_s).should include("private_method_from_trait") - end - - it "should allow the trait to perform metaprogramming acrobatics" do - Doer.class_eval do - does "define_constant_method", "some_method", "some_return_value" - end - instance = Doer.new - instance.should respond_to(:some_method) - instance.some_method.should == "some_return_value" - end - - end - -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9669a3f..85aa730 100755 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,4 @@ $: << File.join(File.dirname(__FILE__), "/../lib" ) require "#{File.dirname(__FILE__)}/../lib/modularity" +require 'rspec_candy/all' From 0e4d72146931f179b479820f22e4174f2404d5cc Mon Sep 17 00:00:00 2001 From: Henning Koch Date: Wed, 8 Jan 2014 13:57:39 +0100 Subject: [PATCH 03/30] Add tests to ensure that including a traited module appends methods outside the trait macro --- spec/as_trait_spec.rb | 66 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/spec/as_trait_spec.rb b/spec/as_trait_spec.rb index a47b67a..bf120cb 100755 --- a/spec/as_trait_spec.rb +++ b/spec/as_trait_spec.rb @@ -71,6 +71,31 @@ def private_method_from_trait end + it 'appends methods outside the trait macro' do + + module HybridModule + + as_trait do + define_method :trait_method do + end + end + + def vanilla_method + end + + end + + @doing_class.class_eval do + include HybridModule + end + + instance = @doing_class.new + + instance.should respond_to(:trait_method) + instance.should respond_to(:vanilla_method) + + end + end describe "with parameters" do @@ -109,6 +134,47 @@ module DoesDefineConstantMethod instance.some_method.should == "some_return_value" end + it "allies to call an unparametrized trait macro with an empty parameter list" do + + module DoesSome + as_trait do + some_trait_included + end + end + + @doing_class.should_receive(:some_trait_included) + + @doing_class.class_eval do + include DoesSome[] + end + + end + + it 'appends methods outside the trait macro' do + + module HybridModuleWithParameters + + as_trait do |name| + define_method name do + end + end + + def vanilla_method + end + + end + + @doing_class.class_eval do + include HybridModuleWithParameters[:trait_method] + end + + instance = @doing_class.new + + instance.should respond_to(:trait_method) + instance.should respond_to(:vanilla_method) + + end + end end From 8e0faf57b7ee6827c15acc9cdf9d3986fcaaa029 Mon Sep 17 00:00:00 2001 From: Henning Koch Date: Wed, 8 Jan 2014 14:01:02 +0100 Subject: [PATCH 04/30] test to assert that multiple traits can be applied --- spec/as_trait_spec.rb | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/spec/as_trait_spec.rb b/spec/as_trait_spec.rb index bf120cb..37917e3 100755 --- a/spec/as_trait_spec.rb +++ b/spec/as_trait_spec.rb @@ -96,6 +96,34 @@ def vanilla_method end + it 'applies multiple trait macros' do + + module FirstTrait + as_trait do + define_method :first do + end + end + end + + module SecondTrait + as_trait do + define_method :second do + end + end + end + + @doing_class.class_eval do + include FirstTrait + include SecondTrait + end + + instance = @doing_class.new + + instance.should respond_to(:first) + instance.should respond_to(:second) + + end + end describe "with parameters" do From 55eadcdbd40a94867e12f0c71f7e7112f56ad87f Mon Sep 17 00:00:00 2001 From: Henning Koch Date: Wed, 8 Jan 2014 17:10:35 +0100 Subject: [PATCH 05/30] migration script modularity1 => 2 --- bin/migrate-modularity1-to-modularity2 | 7 ++ lib/modularity/migrator.rb | 49 +++++++++++ spec/{ => modularity}/as_trait_spec.rb | 0 spec/modularity/migrator_spec.rb | 109 +++++++++++++++++++++++++ 4 files changed, 165 insertions(+) create mode 100755 bin/migrate-modularity1-to-modularity2 create mode 100644 lib/modularity/migrator.rb rename spec/{ => modularity}/as_trait_spec.rb (100%) create mode 100644 spec/modularity/migrator_spec.rb diff --git a/bin/migrate-modularity1-to-modularity2 b/bin/migrate-modularity1-to-modularity2 new file mode 100755 index 0000000..2afb239 --- /dev/null +++ b/bin/migrate-modularity1-to-modularity2 @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby + +require File.expand_path(File.dirname(__FILE__)) + '/../lib/modularity/migrator' + +ARGV.each do |path| + Modularity::Migrator.migrate(path) +end diff --git a/lib/modularity/migrator.rb b/lib/modularity/migrator.rb new file mode 100644 index 0000000..f97d9cd --- /dev/null +++ b/lib/modularity/migrator.rb @@ -0,0 +1,49 @@ +gem 'activesupport' +require 'active_support/all' + +module Modularity + class Migrator + class << self + + def migrate(old_path) + new_path = fix_filename(old_path) + rename(old_path, new_path) unless old_path == new_path + old_code = File.read(new_path) + new_code = fix_code(old_code) + rewrite_file(new_path, new_code) unless old_path == new_path + new_code + end + + private + + def fix_filename(path) + path = File.expand_path(path) + new_path = path.sub(/\/([^\/]+)_trait\.rb$/, '/does_\\1.rb') + new_path + end + + def fix_code(code) + code = code.gsub(/module (.*?)([A-Za-z0-9_]+)Trait\b/, 'module \\1Does\\2') + code = code.gsub(/does ['":]([A-Za-z0-9\_\/]+)(?:'|"|$)(?:,\s*(.*)$)?/) do + trait_path = $1 + parameters = $2 + trait_path = trait_path.sub(/([A-Za-z0-9\_]+)$/, 'does_\\1') + trait_class = trait_path.camelize # don't use classify, it removes plurals! + substituted = "include #{trait_class}" + substituted << "[#{parameters}]" if parameters + substituted + end + code + end + + def rename(old, new) + FileUtils.mv(old, enw) + end + + def rewrite_file(path, content) + File.open(path, "w") { |file| file.write(content) } + end + + end + end +end diff --git a/spec/as_trait_spec.rb b/spec/modularity/as_trait_spec.rb similarity index 100% rename from spec/as_trait_spec.rb rename to spec/modularity/as_trait_spec.rb diff --git a/spec/modularity/migrator_spec.rb b/spec/modularity/migrator_spec.rb new file mode 100644 index 0000000..82c196a --- /dev/null +++ b/spec/modularity/migrator_spec.rb @@ -0,0 +1,109 @@ +require 'spec_helper' + +require 'modularity/migrator' # this is an optional file and thus not loaded automatically + +describe Modularity::Migrator do + + subject do + Modularity::Migrator + end + + describe '.fix_filename' do + + it 'should replace the suffix _trait with a prefix does' do + subject.send(:fix_filename, '/path/to/search_trait.rb').should == '/path/to/does_search.rb' + end + + it "should not rename files that don't end in _trait.rb" do + subject.send(:fix_filename, '/path/to/search.rb').should == '/path/to/search.rb' + end + + end + + describe '.fix_code' do + + it 'renames a module FooBarTrait to DoesFooBar' do + + old_code = <<-RUBY + module Namespace::FooBarTrait + as_trait do + define_method :foo do + end + define_method :bar do + end + end + end + RUBY + + new_code = <<-RUBY + module Namespace::DoesFooBar + as_trait do + define_method :foo do + end + define_method :bar do + end + end + end + RUBY + + subject.send(:fix_code, old_code).should == new_code + end + + it "does not rename modules that aren't traits" do + + old_code = <<-RUBY + module Namespace::FooBar + def foo + end + def bar + end + end + RUBY + + subject.send(:fix_code, old_code).should == old_code + end + + it 'replaces does calls with include' do + + old_code = <<-RUBY + class User < ActiveRecord::Base + does 'user/search' + does 'user/account_settings' + does 'trashable' + end + RUBY + + new_code = <<-RUBY + class User < ActiveRecord::Base + include User::DoesSearch + include User::DoesAccountSettings + include DoesTrashable + end + RUBY + + subject.send(:fix_code, old_code).should == new_code + end + + it 'puts does parameters into square brackets' do + + old_code = <<-RUBY + class User < ActiveRecord::Base + does 'flag', :active, :default => true + does 'record/search', :field => :email + end + RUBY + + new_code = <<-RUBY + class User < ActiveRecord::Base + include DoesFlag[:active, :default => true] + include Record::DoesSearch[:field => :email] + end + RUBY + + subject.send(:fix_code, old_code).should == new_code + + end + + end + +end \ No newline at end of file From 22354692b72e9b1b3fe8c205216809a98195fd0d Mon Sep 17 00:00:00 2001 From: Henning Koch Date: Wed, 8 Jan 2014 18:07:31 +0100 Subject: [PATCH 06/30] Bump version, rewrite README in markdown and for version 2, fix migration script --- README.md | 122 +++++++++++++++++++++++++++++++ README.rdoc | 107 --------------------------- lib/modularity/migrator.rb | 8 +- lib/modularity/version.rb | 2 +- spec/modularity/migrator_spec.rb | 2 +- 5 files changed, 130 insertions(+), 111 deletions(-) create mode 100755 README.md delete mode 100755 README.rdoc diff --git a/README.md b/README.md new file mode 100755 index 0000000..7fd4fbb --- /dev/null +++ b/README.md @@ -0,0 +1,122 @@ +Modularity 2 - Traits and partial classes for Ruby +================================================== + +Modularity enhances Ruby's [`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. + +Note that this is **Modularity 2**, which has a different syntax older version. +Modularity 1 users can use [a script to migrate their code](#migrating-from-modularity-1) +or use the [modularity1 branch](https://github.com/makandra/modularity/tree/modularity1). + + +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: + + # app/models/article.rb + class Article + 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 + +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: + + # 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: + + # app/models/user.rb + class User < ActiveRecord::Base + include User::DoesAuthentication + include User::DoesAddress + 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. + + +Installation +------------ + + sudo gem install modularity + + +Credits +------- + +Henning Koch from [makandra.com](http://makandra.com/) + diff --git a/README.rdoc b/README.rdoc deleted file mode 100755 index 3190ea7..0000000 --- a/README.rdoc +++ /dev/null @@ -1,107 +0,0 @@ -= modularity - Traits and partial classes for Ruby - -Modularity provides traits and partial classes for Ruby. -This allows very simple definition of meta-programming macros, -as you might now from acts_as_something type of plugins, -or the macros Rails provides for your models. This also lets you organize -large models into multiple source files in a way that is less awkward -than using modules. - -Modularity traits are to your models what partials are for your Rails views. - -== 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: - - # app/models/article.rb - class Article - does "strip_fields", :name, :brand - end - - # app/models/shared/strip_fields_trait.rb - module StripFieldsTrait - as_trait do |*fields| - fields.each do |field| - define_method("#{field}=") do |value| - self[field] = value.strip - end - end - end - end - -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: - - # app/models/model.rb - class Model - does "mixin" - end - - # app/models/mixin_trait.rb - module MixinTrait - as_trait do - def instance_method - # ... - end - def self.class_method - # .. - 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: - - # app/models/user.rb - class User < ActiveRecord::Base - does "user/authentication" - does "user/address" - end - - # app/models/user/authentication_trait.rb - module User::AuthenticationTrait - as_trait do - # methods, validations, etc. regarding usernames and passwords go here - end - end - - # app/models/user/permissions_trait.rb - module User::PermissionsTrait - as_trait do - # methods, validations, etc. regarding contact information go here - end - end - -== Installation - - sudo gem install modularity - - -== Note if you're still on Ruby 1.8.6 - -Modularity requires Ruby 1.8.7. Earlier versions are missing class_exec. You might be able to hack in class_exec -using {this}[http://github.com/brynary/rspec/blob/f80d61a399b34f58084a378c85a43a95ff484619/lib/spec/extensions/instance_exec.rb] as a guide, but it's not pretty. - -== Credits - -Henning Koch - -{makandra.com}[http://makandra.com/] - -{gem-session.com}[http://gem-session.com/] diff --git a/lib/modularity/migrator.rb b/lib/modularity/migrator.rb index f97d9cd..ed8733b 100644 --- a/lib/modularity/migrator.rb +++ b/lib/modularity/migrator.rb @@ -1,16 +1,20 @@ gem 'activesupport' require 'active_support/all' +require 'fileutils' module Modularity class Migrator class << self def migrate(old_path) + old_path = File.expand_path(old_path) new_path = fix_filename(old_path) rename(old_path, new_path) unless old_path == new_path old_code = File.read(new_path) new_code = fix_code(old_code) - rewrite_file(new_path, new_code) unless old_path == new_path + rewrite_file(new_path, new_code) unless old_code == new_code + puts "Migrated #{old_path}" + `ruby -c #{new_path}` new_code end @@ -37,7 +41,7 @@ def fix_code(code) end def rename(old, new) - FileUtils.mv(old, enw) + FileUtils.mv(old, new) end def rewrite_file(path, content) diff --git a/lib/modularity/version.rb b/lib/modularity/version.rb index b84bf07..3c9469c 100644 --- a/lib/modularity/version.rb +++ b/lib/modularity/version.rb @@ -1,3 +1,3 @@ module Modularity - VERSION = '0.6.1' + VERSION = '2.0.0' end diff --git a/spec/modularity/migrator_spec.rb b/spec/modularity/migrator_spec.rb index 82c196a..05ce32a 100644 --- a/spec/modularity/migrator_spec.rb +++ b/spec/modularity/migrator_spec.rb @@ -106,4 +106,4 @@ class User < ActiveRecord::Base end -end \ No newline at end of file +end From 5ae0dc9dabef1f3a43f08c159bb2999af1848d11 Mon Sep 17 00:00:00 2001 From: Henning Koch Date: Wed, 8 Jan 2014 18:11:46 +0100 Subject: [PATCH 07/30] Document migration script --- README.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7fd4fbb..5928e2b 100755 --- a/README.md +++ b/README.md @@ -112,7 +112,33 @@ to decompose a huge Ruby class. Installation ------------ - sudo gem install modularity +Add the following to your `Gemfile`: + + gem 'modularity', '>=2' + +Now run `bundle install`. + + +Migrating from Modularity 1 +--------------------------- + +If you have been using Modularity 1 with the `does` syntax, we provide a script to migrate your Ruby project +automatically. + +1. Make sure your project has tests and you have a backup of your files (or pushed your commits to Git) + +2. From your project directory, do this: + + find . -name "*.rb" | migrate-modularity1-to-modularity2 + +3. The script will rename your files and change your code. It will also syntax-check your files after conversion + (since the script is not perfect). + +4. Check the diff to see what the script has done. + +5. Run tests to see if everything still works. + + Credits From e9df53ccec48696f636f32cc688cf8df4c60a6af Mon Sep 17 00:00:00 2001 From: Henning Koch Date: Wed, 8 Jan 2014 18:17:23 +0100 Subject: [PATCH 08/30] fix README --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5928e2b..33e4d6e 100755 --- a/README.md +++ b/README.md @@ -42,7 +42,9 @@ Here is an example of a `strip_field` macro, which created setter methods that r 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. @@ -84,7 +86,7 @@ partial classes, so each file can deal with a single aspect of your model: # app/models/user.rb class User < ActiveRecord::Base include User::DoesAuthentication - include User::DoesAddress + include User::DoesPermissions end # app/models/user/does_authentication.rb From cb6ab2121829f1eb7a60c47f5ff5d4e1e4ff260f Mon Sep 17 00:00:00 2001 From: Henning Koch Date: Thu, 9 Jan 2014 13:40:53 +0100 Subject: [PATCH 09/30] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 33e4d6e..725fdc0 100755 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ 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: # app/models/article.rb - class Article + class Article < ActiveRecord::Base include DoesStripFields[:name, :brand] end @@ -85,8 +85,8 @@ partial classes, so each file can deal with a single aspect of your model: # app/models/user.rb class User < ActiveRecord::Base - include User::DoesAuthentication - include User::DoesPermissions + include DoesAuthentication + include DoesPermissions end # app/models/user/does_authentication.rb From 971873f616814fe9fa708c72572b6c812b96c32d Mon Sep 17 00:00:00 2001 From: Henning Koch Date: Mon, 13 Jan 2014 08:14:12 +0100 Subject: [PATCH 10/30] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 725fdc0..1fd55af 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Modularity 2 - Traits and partial classes for Ruby ================================================== -Modularity enhances Ruby's [`Module`] so it can be used traits and partial classes. +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. From df8ee3b0af227086b8f6b34432e2ec8f9ae3b3b3 Mon Sep 17 00:00:00 2001 From: Tobias Kraze Date: Tue, 4 Feb 2014 12:23:28 +0100 Subject: [PATCH 11/30] fix migration script to read filenames from STDIN --- bin/migrate-modularity1-to-modularity2 | 4 ++-- lib/modularity/version.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/migrate-modularity1-to-modularity2 b/bin/migrate-modularity1-to-modularity2 index 2afb239..3bb149e 100755 --- a/bin/migrate-modularity1-to-modularity2 +++ b/bin/migrate-modularity1-to-modularity2 @@ -2,6 +2,6 @@ require File.expand_path(File.dirname(__FILE__)) + '/../lib/modularity/migrator' -ARGV.each do |path| - Modularity::Migrator.migrate(path) +ARGF.each do |path| + Modularity::Migrator.migrate(path.strip) end diff --git a/lib/modularity/version.rb b/lib/modularity/version.rb index 3c9469c..e8322d8 100644 --- a/lib/modularity/version.rb +++ b/lib/modularity/version.rb @@ -1,3 +1,3 @@ module Modularity - VERSION = '2.0.0' + VERSION = '2.0.1' end From 7e3ccaf6121b7332b1a15695ba1cba2374457368 Mon Sep 17 00:00:00 2001 From: Simon Stemplinger Date: Sun, 9 Nov 2014 12:09:26 +0100 Subject: [PATCH 12/30] add license to gemspec --- modularity.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/modularity.gemspec b/modularity.gemspec index ac5015b..f479b00 100755 --- a/modularity.gemspec +++ b/modularity.gemspec @@ -5,6 +5,7 @@ require 'modularity/version' Gem::Specification.new do |s| s.name = %q{modularity} s.version = Modularity::VERSION + s.licenses = ["MIT"] s.authors = ["Henning Koch"] s.email = %q{github@makandra.de} s.homepage = %q{http://github.com/makandra/modularity} From 91cc0d6901572e44dc3159f1863b986f14b0b52d Mon Sep 17 00:00:00 2001 From: Emanuel Denzel Date: Tue, 7 Aug 2018 17:52:11 +0200 Subject: [PATCH 13/30] Add a CHANGELOG --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..67685cc --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added +- This CHANGELOG file. + From d93f2366dec942f0c30d5936f852e4eb97232d21 Mon Sep 17 00:00:00 2001 From: Emanuel Denzel Date: Thu, 23 Aug 2018 17:19:29 +0200 Subject: [PATCH 14/30] Update the changelog to format https://makandracards.com/makandra/54223-how-to-write-a-good-changelog --- CHANGELOG.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67685cc..cda8844 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,10 @@ # Changelog All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## [Unreleased] -### Added -- This CHANGELOG file. +## Unreleased +### Compatible changes +- This CHANGELOG file. From efa8809a8b529551e09ebb3f5278bbcdac62335e Mon Sep 17 00:00:00 2001 From: Emanuel Denzel Date: Tue, 24 Aug 2021 15:02:40 +0200 Subject: [PATCH 15/30] Remove migration code for upgrading to version 2 --- CHANGELOG.md | 5 +- README.md | 160 ++++++++++--------------- bin/migrate-modularity1-to-modularity2 | 7 -- lib/modularity/migrator.rb | 53 -------- spec/modularity/migrator_spec.rb | 109 ----------------- 5 files changed, 69 insertions(+), 265 deletions(-) delete mode 100755 bin/migrate-modularity1-to-modularity2 delete mode 100644 lib/modularity/migrator.rb delete mode 100644 spec/modularity/migrator_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index cda8844..5638170 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,11 @@ 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 + +- Removed migration guide for modularity version 1. + ### Compatible changes - This CHANGELOG file. diff --git a/README.md b/README.md index 1fd55af..43353d7 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -Modularity 2 - Traits and partial classes for Ruby -================================================== +# Modularity 2 - 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 @@ -8,13 +7,17 @@ This allows very simple definition of meta-programming macros like the Modularity also lets you organize large models into multiple source files in a way that is less awkward than using modules. -Note that this is **Modularity 2**, which has a different syntax older version. -Modularity 1 users can use [a script to migrate their code](#migrating-from-modularity-1) -or use the [modularity1 branch](https://github.com/makandra/modularity/tree/modularity1). +## Installation +Add the following to your `Gemfile`: + +``` +gem 'modularity' +``` -Example 1: Easy meta-programming macros ----------------------------------------- +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, @@ -27,81 +30,83 @@ 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: - # 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 +``` +# 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 ------------------------------------- +## 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: - # app/models/model.rb - class Model - include Mixin +``` +# app/models/model.rb +class Model + include Mixin +end + +# app/models/mixin.rb +module Mixin + as_trait do + def instance_method + # ... end - - # app/models/mixin.rb - module Mixin - as_trait do - def instance_method - # ... - end - def self.class_method - # .. - end - 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 -------------------------------------------------------- +## 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: - # 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 +``` +# 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 @@ -110,41 +115,6 @@ 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. - -Installation ------------- - -Add the following to your `Gemfile`: - - gem 'modularity', '>=2' - -Now run `bundle install`. - - -Migrating from Modularity 1 ---------------------------- - -If you have been using Modularity 1 with the `does` syntax, we provide a script to migrate your Ruby project -automatically. - -1. Make sure your project has tests and you have a backup of your files (or pushed your commits to Git) - -2. From your project directory, do this: - - find . -name "*.rb" | migrate-modularity1-to-modularity2 - -3. The script will rename your files and change your code. It will also syntax-check your files after conversion - (since the script is not perfect). - -4. Check the diff to see what the script has done. - -5. Run tests to see if everything still works. - - - - -Credits -------- +## Credits Henning Koch from [makandra.com](http://makandra.com/) - diff --git a/bin/migrate-modularity1-to-modularity2 b/bin/migrate-modularity1-to-modularity2 deleted file mode 100755 index 3bb149e..0000000 --- a/bin/migrate-modularity1-to-modularity2 +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env ruby - -require File.expand_path(File.dirname(__FILE__)) + '/../lib/modularity/migrator' - -ARGF.each do |path| - Modularity::Migrator.migrate(path.strip) -end diff --git a/lib/modularity/migrator.rb b/lib/modularity/migrator.rb deleted file mode 100644 index ed8733b..0000000 --- a/lib/modularity/migrator.rb +++ /dev/null @@ -1,53 +0,0 @@ -gem 'activesupport' -require 'active_support/all' -require 'fileutils' - -module Modularity - class Migrator - class << self - - def migrate(old_path) - old_path = File.expand_path(old_path) - new_path = fix_filename(old_path) - rename(old_path, new_path) unless old_path == new_path - old_code = File.read(new_path) - new_code = fix_code(old_code) - rewrite_file(new_path, new_code) unless old_code == new_code - puts "Migrated #{old_path}" - `ruby -c #{new_path}` - new_code - end - - private - - def fix_filename(path) - path = File.expand_path(path) - new_path = path.sub(/\/([^\/]+)_trait\.rb$/, '/does_\\1.rb') - new_path - end - - def fix_code(code) - code = code.gsub(/module (.*?)([A-Za-z0-9_]+)Trait\b/, 'module \\1Does\\2') - code = code.gsub(/does ['":]([A-Za-z0-9\_\/]+)(?:'|"|$)(?:,\s*(.*)$)?/) do - trait_path = $1 - parameters = $2 - trait_path = trait_path.sub(/([A-Za-z0-9\_]+)$/, 'does_\\1') - trait_class = trait_path.camelize # don't use classify, it removes plurals! - substituted = "include #{trait_class}" - substituted << "[#{parameters}]" if parameters - substituted - end - code - end - - def rename(old, new) - FileUtils.mv(old, new) - end - - def rewrite_file(path, content) - File.open(path, "w") { |file| file.write(content) } - end - - end - end -end diff --git a/spec/modularity/migrator_spec.rb b/spec/modularity/migrator_spec.rb deleted file mode 100644 index 05ce32a..0000000 --- a/spec/modularity/migrator_spec.rb +++ /dev/null @@ -1,109 +0,0 @@ -require 'spec_helper' - -require 'modularity/migrator' # this is an optional file and thus not loaded automatically - -describe Modularity::Migrator do - - subject do - Modularity::Migrator - end - - describe '.fix_filename' do - - it 'should replace the suffix _trait with a prefix does' do - subject.send(:fix_filename, '/path/to/search_trait.rb').should == '/path/to/does_search.rb' - end - - it "should not rename files that don't end in _trait.rb" do - subject.send(:fix_filename, '/path/to/search.rb').should == '/path/to/search.rb' - end - - end - - describe '.fix_code' do - - it 'renames a module FooBarTrait to DoesFooBar' do - - old_code = <<-RUBY - module Namespace::FooBarTrait - as_trait do - define_method :foo do - end - define_method :bar do - end - end - end - RUBY - - new_code = <<-RUBY - module Namespace::DoesFooBar - as_trait do - define_method :foo do - end - define_method :bar do - end - end - end - RUBY - - subject.send(:fix_code, old_code).should == new_code - end - - it "does not rename modules that aren't traits" do - - old_code = <<-RUBY - module Namespace::FooBar - def foo - end - def bar - end - end - RUBY - - subject.send(:fix_code, old_code).should == old_code - end - - it 'replaces does calls with include' do - - old_code = <<-RUBY - class User < ActiveRecord::Base - does 'user/search' - does 'user/account_settings' - does 'trashable' - end - RUBY - - new_code = <<-RUBY - class User < ActiveRecord::Base - include User::DoesSearch - include User::DoesAccountSettings - include DoesTrashable - end - RUBY - - subject.send(:fix_code, old_code).should == new_code - end - - it 'puts does parameters into square brackets' do - - old_code = <<-RUBY - class User < ActiveRecord::Base - does 'flag', :active, :default => true - does 'record/search', :field => :email - end - RUBY - - new_code = <<-RUBY - class User < ActiveRecord::Base - include DoesFlag[:active, :default => true] - include Record::DoesSearch[:field => :email] - end - RUBY - - subject.send(:fix_code, old_code).should == new_code - - end - - end - -end From f28357a5d6c4a23454154756377005d83477a81a Mon Sep 17 00:00:00 2001 From: Emanuel Denzel Date: Tue, 24 Aug 2021 15:04:24 +0200 Subject: [PATCH 16/30] Upgrade to RSpec 3 --- .gitignore | 1 - .rspec | 1 + CHANGELOG.md | 3 ++- Gemfile | 4 +++ Gemfile.lock | 45 ++++++++++++++++++++++++++++++++ Rakefile | 14 ++++------ bin/console | 9 +++++++ modularity.gemspec | 5 ---- spec/modularity/as_trait_spec.rb | 2 -- spec/rcov.opts | 2 -- spec/spec.opts | 4 --- spec/spec_helper.rb | 8 +++--- 12 files changed, 71 insertions(+), 27 deletions(-) create mode 100644 .rspec create mode 100644 Gemfile.lock create mode 100755 bin/console delete mode 100755 spec/rcov.opts delete mode 100755 spec/spec.opts diff --git a/.gitignore b/.gitignore index 6d88d9c..8c0f972 100755 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,3 @@ doc pkg *.gem .idea -Gemfile.lock diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..c99d2e7 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--require spec_helper diff --git a/CHANGELOG.md b/CHANGELOG.md index 5638170..5e84cd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,4 +10,5 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html - Removed migration guide for modularity version 1. ### Compatible changes -- This CHANGELOG file. + +- Added this CHANGELOG file. diff --git a/Gemfile b/Gemfile index c80ee36..0c50bee 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,7 @@ source "http://rubygems.org" gemspec + +gem 'rake' +gem 'rspec' +gem 'pry-byebug' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..811353e --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,45 @@ +PATH + remote: . + specs: + modularity (2.0.1) + +GEM + remote: http://rubygems.org/ + specs: + byebug (11.1.3) + coderay (1.1.3) + diff-lcs (1.4.4) + 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 + modularity! + pry-byebug + rake + rspec + +BUNDLED WITH + 1.17.3 diff --git a/Rakefile b/Rakefile index 8c158fe..b1f046f 100755 --- a/Rakefile +++ b/Rakefile @@ -1,12 +1,8 @@ -require 'rake' -require 'spec/rake/spectask' require 'bundler/gem_tasks' +require 'rspec/core/rake_task' -desc 'Default: Run all specs.' -task :default => :spec - -desc "Run all specs" -Spec::Rake::SpecTask.new() do |t| - t.spec_opts = ['--options', "\"spec/spec.opts\""] - t.spec_files = FileList['spec/**/*_spec.rb'] +RSpec::Core::RakeTask.new(:spec) do |task| + task.verbose = false end + +task default: :spec diff --git a/bin/console b/bin/console new file mode 100755 index 0000000..5f3a90a --- /dev/null +++ b/bin/console @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby + +require 'bundler/setup' +require 'modularity' +require 'pry' + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. +Pry.start diff --git a/modularity.gemspec b/modularity.gemspec index f479b00..1064825 100755 --- a/modularity.gemspec +++ b/modularity.gemspec @@ -16,9 +16,4 @@ Gem::Specification.new do |s| s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] - - s.add_development_dependency('rake') - s.add_development_dependency('rspec', '<2') - s.add_development_dependency('rspec_candy') - end diff --git a/spec/modularity/as_trait_spec.rb b/spec/modularity/as_trait_spec.rb index 37917e3..1d57788 100755 --- a/spec/modularity/as_trait_spec.rb +++ b/spec/modularity/as_trait_spec.rb @@ -1,5 +1,3 @@ -require 'spec_helper' - describe Modularity::AsTrait do describe '.included' do diff --git a/spec/rcov.opts b/spec/rcov.opts deleted file mode 100755 index 274ed51..0000000 --- a/spec/rcov.opts +++ /dev/null @@ -1,2 +0,0 @@ ---exclude "spec/*,gems/*" ---rails \ No newline at end of file diff --git a/spec/spec.opts b/spec/spec.opts deleted file mode 100755 index 391705b..0000000 --- a/spec/spec.opts +++ /dev/null @@ -1,4 +0,0 @@ ---colour ---format progress ---loadby mtime ---reverse diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 85aa730..b86b309 100755 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,4 +1,6 @@ -$: << File.join(File.dirname(__FILE__), "/../lib" ) +require 'modularity' -require "#{File.dirname(__FILE__)}/../lib/modularity" -require 'rspec_candy/all' +RSpec.configure do |config| + config.expect_with(:rspec) { |expects| expects.syntax = :should } + config.mock_with(:rspec) { |mocks| mocks.syntax = [:should, :receive] } +end From f377908001bea0d8c23c43a53dd4f9c8cea82724 Mon Sep 17 00:00:00 2001 From: Emanuel Denzel Date: Tue, 24 Aug 2021 15:12:40 +0200 Subject: [PATCH 17/30] Update rubygems config and github defaults --- LICENSE.txt | 21 +++++++++++++++++++++ MIT-LICENSE | 20 -------------------- modularity.gemspec | 38 +++++++++++++++++++++++--------------- 3 files changed, 44 insertions(+), 35 deletions(-) create mode 100644 LICENSE.txt delete mode 100755 MIT-LICENSE diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..646e18a --- /dev/null +++ b/LICENSE.txt @@ -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. diff --git a/MIT-LICENSE b/MIT-LICENSE deleted file mode 100755 index 30adc46..0000000 --- a/MIT-LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -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. diff --git a/modularity.gemspec b/modularity.gemspec index 1064825..8ff303b 100755 --- a/modularity.gemspec +++ b/modularity.gemspec @@ -1,19 +1,27 @@ -# -*- encoding: utf-8 -*- -$:.push File.expand_path("../lib", __FILE__) +lib = File.expand_path('lib', __dir__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'modularity/version' -Gem::Specification.new do |s| - s.name = %q{modularity} - s.version = Modularity::VERSION - s.licenses = ["MIT"] - s.authors = ["Henning Koch"] - s.email = %q{github@makandra.de} - s.homepage = %q{http://github.com/makandra/modularity} - s.summary = %q{Traits and partial classes for Ruby} - s.description = %q{Traits and partial classes for Ruby} +Gem::Specification.new do |spec| + spec.name = 'modularity' + spec.version = Modularity::VERSION + spec.required_ruby_version = '>= 2.5.0' + spec.authors = ['Henning Koch'] + spec.email = ['henning.koch@makandra.de'] - s.files = `git ls-files`.split("\n") - s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") - s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } - s.require_paths = ["lib"] + spec.summary = 'Traits and partial classes for Ruby' + spec.description = 'Traits and partial classes for Ruby' + spec.homepage = 'https://github.com/makandra/modularity' + spec.license = 'MIT' + + # Specify which files should be added to the gem when it is released. + # The `git ls-files -z` loads the files in the RubyGem that have been added into git. + spec.files = Dir.chdir(File.expand_path(__dir__)) do + `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } + end + spec.bindir = 'exe' + spec.executables = spec.files.grep(%r(^exe/)) { |f| File.basename(f) } + spec.require_paths = ['lib'] + + # Development dependencies are defined in the Gemfile (therefore no `spec.add_development_dependency` directives) end From 452b76a608b007b8bac9432cb8a65d1aa013a32b Mon Sep 17 00:00:00 2001 From: Emanuel Denzel Date: Tue, 24 Aug 2021 15:55:06 +0200 Subject: [PATCH 18/30] Add gemika and Github actions for testing --- .github/workflows/test.yml | 36 ++++++++++++++++++++++++++++++++++++ .ruby-version | 1 + CHANGELOG.md | 1 + Gemfile | 3 ++- Gemfile.lock | 4 +++- README.md | 8 ++++++++ Rakefile | 9 +++------ 7 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 .ruby-version diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..d5d36b2 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,36 @@ +--- +name: Tests +'on': + push: + branches: + - master + pull_request: + branches: + - master +jobs: + test: + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + include: + - ruby: 2.5.7 + gemfile: Gemfile + - ruby: 2.7.4 + gemfile: Gemfile + - ruby: 3.0.2 + 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.2.22 + bundle install --no-deployment + - name: Run tests + run: bundle exec rspec diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..35d16fb --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.5.7 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e84cd8..3be3d3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Breaking changes - Removed migration guide for modularity version 1. +- Removed support for Ruby < `2.5.0`. ### Compatible changes diff --git a/Gemfile b/Gemfile index 0c50bee..f0d494f 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,8 @@ -source "http://rubygems.org" +source 'http://rubygems.org' gemspec gem 'rake' gem 'rspec' gem 'pry-byebug' +gem 'gemika' diff --git a/Gemfile.lock b/Gemfile.lock index 811353e..b9be766 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,6 +9,7 @@ GEM byebug (11.1.3) coderay (1.1.3) diff-lcs (1.4.4) + gemika (0.6.1) method_source (1.0.0) pry (0.13.1) coderay (~> 1.1) @@ -36,10 +37,11 @@ PLATFORMS x86_64-linux DEPENDENCIES + gemika modularity! pry-byebug rake rspec BUNDLED WITH - 1.17.3 + 2.2.22 diff --git a/README.md b/README.md index 43353d7..6953e73 100755 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![Tests](https://github.com/makandra/modularity/workflows/Tests/badge.svg)](https://github.com/makandra/modularity/actions) + # Modularity 2 - 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. @@ -115,6 +117,12 @@ 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/) diff --git a/Rakefile b/Rakefile index b1f046f..666a2e5 100755 --- a/Rakefile +++ b/Rakefile @@ -1,8 +1,5 @@ require 'bundler/gem_tasks' -require 'rspec/core/rake_task' +require 'bundler/setup' +require 'gemika/tasks' -RSpec::Core::RakeTask.new(:spec) do |task| - task.verbose = false -end - -task default: :spec +task default: 'matrix:spec' From be12d70bd9026210a4da16b8395cbc8fd6180558 Mon Sep 17 00:00:00 2001 From: Emanuel Denzel Date: Tue, 24 Aug 2021 16:05:14 +0200 Subject: [PATCH 19/30] Bump version from 2.0.1 to 3.0.0 --- CHANGELOG.md | 7 +++++++ Gemfile.lock | 4 ++-- lib/modularity/version.rb | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3be3d3c..18d8100 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Breaking changes +### Compatible changes + + +## 3.0.0 - 2021-08-24 + +### Breaking changes + - Removed migration guide for modularity version 1. - Removed support for Ruby < `2.5.0`. diff --git a/Gemfile.lock b/Gemfile.lock index b9be766..8720fcd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - modularity (2.0.1) + modularity (3.0.0) GEM remote: http://rubygems.org/ @@ -44,4 +44,4 @@ DEPENDENCIES rspec BUNDLED WITH - 2.2.22 + 2.2.26 diff --git a/lib/modularity/version.rb b/lib/modularity/version.rb index e8322d8..7b39506 100644 --- a/lib/modularity/version.rb +++ b/lib/modularity/version.rb @@ -1,3 +1,3 @@ module Modularity - VERSION = '2.0.1' + VERSION = '3.0.0' end From 3c19c84363a5d9f499eae4bf7f49427a919bdb46 Mon Sep 17 00:00:00 2001 From: Emanuel Denzel Date: Tue, 24 Aug 2021 16:07:33 +0200 Subject: [PATCH 20/30] Remove version from title --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6953e73..683645c 100755 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Tests](https://github.com/makandra/modularity/workflows/Tests/badge.svg)](https://github.com/makandra/modularity/actions) -# Modularity 2 - Traits and partial classes for Ruby +# 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 From 20373fc7c41b65f1a1029cab75cfe0b687adffd2 Mon Sep 17 00:00:00 2001 From: Niklas Hasselmeyer Date: Thu, 10 Feb 2022 16:41:13 +0100 Subject: [PATCH 21/30] Activate rubygems MFA --- modularity.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/modularity.gemspec b/modularity.gemspec index 8ff303b..77d626f 100755 --- a/modularity.gemspec +++ b/modularity.gemspec @@ -13,6 +13,7 @@ Gem::Specification.new do |spec| spec.description = 'Traits and partial classes for Ruby' spec.homepage = 'https://github.com/makandra/modularity' spec.license = 'MIT' + spec.metadata = { 'rubygems_mfa_required' => 'true' } # Specify which files should be added to the gem when it is released. # The `git ls-files -z` loads the files in the RubyGem that have been added into git. From 17b72537c6ec84a11eacf5eec6abe0b0d3b48edb Mon Sep 17 00:00:00 2001 From: Bruno Sedler Date: Wed, 9 Mar 2022 16:37:43 +0100 Subject: [PATCH 22/30] Bump version from 3.0.0 to 3.0.1 --- CHANGELOG.md | 7 +++++++ Gemfile.lock | 4 ++-- lib/modularity/version.rb | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18d8100..7f59ef8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Compatible changes +## 3.0.1 - 2022-03-09 + +### Compatible changes + +- Activate Rubygems MFA + + ## 3.0.0 - 2021-08-24 ### Breaking changes diff --git a/Gemfile.lock b/Gemfile.lock index 8720fcd..68730eb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - modularity (3.0.0) + modularity (3.0.1) GEM remote: http://rubygems.org/ @@ -44,4 +44,4 @@ DEPENDENCIES rspec BUNDLED WITH - 2.2.26 + 2.2.32 diff --git a/lib/modularity/version.rb b/lib/modularity/version.rb index 7b39506..9ca6d7e 100644 --- a/lib/modularity/version.rb +++ b/lib/modularity/version.rb @@ -1,3 +1,3 @@ module Modularity - VERSION = '3.0.0' + VERSION = '3.0.1' end From cf62df69267b6b63457ad2c001ab77c8aadd7272 Mon Sep 17 00:00:00 2001 From: Bruno Sedler Date: Fri, 20 May 2022 14:55:53 +0200 Subject: [PATCH 23/30] Add support for separation of positional and keyword arguments in ruby 3 --- .github/workflows/test.yml | 4 ++++ lib/modularity/as_trait.rb | 22 +++++++++++++++++----- spec/modularity/as_trait_spec.rb | 29 +++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d5d36b2..34b602b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,10 +16,14 @@ jobs: 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 env: BUNDLE_GEMFILE: "${{ matrix.gemfile }}" steps: diff --git a/lib/modularity/as_trait.rb b/lib/modularity/as_trait.rb index f1145bd..bbc3f0a 100755 --- a/lib/modularity/as_trait.rb +++ b/lib/modularity/as_trait.rb @@ -2,14 +2,19 @@ module Modularity class ParametrizedTrait < Module - def initialize(blank_trait, args) + def initialize(blank_trait, args, kwargs) @args = args + @kwargs = kwargs @macro = blank_trait.instance_variable_get(:@modularity_macro) include(blank_trait) end def included(base) - base.class_exec(*@args, &@macro) + if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7') + base.class_exec(*@args, &@macro) + else + base.class_exec(*@args, **@kwargs, &@macro) + end end end @@ -27,9 +32,16 @@ def self.included(base) end - def self.[](*args) - blank_trait = self - ParametrizedTrait.new(blank_trait, args) + if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7') + def self.[](*args) + blank_trait = self + ParametrizedTrait.new(blank_trait, args, {}) + end + else + def self.[](*args, **kwargs) + blank_trait = self + ParametrizedTrait.new(blank_trait, args, kwargs) + end end end diff --git a/spec/modularity/as_trait_spec.rb b/spec/modularity/as_trait_spec.rb index 1d57788..d0cca6a 100755 --- a/spec/modularity/as_trait_spec.rb +++ b/spec/modularity/as_trait_spec.rb @@ -201,6 +201,35 @@ def vanilla_method end + it 'passes keyword args to the block given to as_trait' do + + module ModuleWithKeywordArgs + as_trait do |hash, required_kwarg:, optional_kwarg: 'foo'| + define_method :passed_hash do + hash + end + + define_method :required_keyword do + required_kwarg + end + + define_method :optional_keyword do + optional_kwarg + end + + end + end + + @doing_class.class_eval do + include ModuleWithKeywordArgs[{ first_hash_key: 'value_one', second_hash_key: 'value_two' }, required_kwarg: 'bar'] + end + + instance = @doing_class.new + instance.passed_hash.should eq({ first_hash_key: 'value_one', second_hash_key: 'value_two' }) + instance.required_keyword.should eq('bar') + instance.optional_keyword.should eq('foo') + end + end end From 8fe03e0291988f63cca53e1f12849ea655e508d4 Mon Sep 17 00:00:00 2001 From: Bruno Sedler Date: Wed, 1 Jun 2022 17:58:53 +0200 Subject: [PATCH 24/30] Bump version from 3.0.1 to 3.1.0 --- CHANGELOG.md | 7 +++++++ Gemfile.lock | 2 +- lib/modularity/version.rb | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f59ef8..8a49c59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Compatible changes +## 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 diff --git a/Gemfile.lock b/Gemfile.lock index 68730eb..b2cbd89 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - modularity (3.0.1) + modularity (3.1.0) GEM remote: http://rubygems.org/ diff --git a/lib/modularity/version.rb b/lib/modularity/version.rb index 9ca6d7e..7fcb430 100644 --- a/lib/modularity/version.rb +++ b/lib/modularity/version.rb @@ -1,3 +1,3 @@ module Modularity - VERSION = '3.0.1' + VERSION = '3.1.0' end From 2bfdf44e0df18383d984ff0d34f4d3ff1f312f6e Mon Sep 17 00:00:00 2001 From: Henning Koch Date: Wed, 5 Oct 2022 13:11:15 +0200 Subject: [PATCH 25/30] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 683645c..8937d56 100755 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ in a way that is less awkward than using modules. Add the following to your `Gemfile`: -``` +```ruby gem 'modularity' ``` @@ -32,7 +32,7 @@ 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] @@ -61,7 +61,7 @@ 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 @@ -88,7 +88,7 @@ Models are often concerned with multiple themes like "authentication", "contact 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 From f3e8972c3b141a32c4eace5f36d4d2f6e1501b84 Mon Sep 17 00:00:00 2001 From: Bruno Sedler Date: Wed, 22 Feb 2023 09:56:09 +0100 Subject: [PATCH 26/30] Add support for Ruby 3.2 --- .github/workflows/test.yml | 2 ++ CHANGELOG.md | 2 ++ Gemfile.lock | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 34b602b..79e2a05 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,6 +24,8 @@ jobs: gemfile: Gemfile - ruby: 3.1.2 gemfile: Gemfile + - ruby: 3.2.1 + gemfile: Gemfile env: BUNDLE_GEMFILE: "${{ matrix.gemfile }}" steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a49c59..0e4e865 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Compatible changes +- Add support for Ruby 3.2 + ## 3.1.0 - 2022-06-01 diff --git a/Gemfile.lock b/Gemfile.lock index b2cbd89..fd170f6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,7 +9,7 @@ GEM byebug (11.1.3) coderay (1.1.3) diff-lcs (1.4.4) - gemika (0.6.1) + gemika (0.8.1) method_source (1.0.0) pry (0.13.1) coderay (~> 1.1) From 9d08cf37ad4d1454533e539a41b62aba06842313 Mon Sep 17 00:00:00 2001 From: Bruno Sedler Date: Wed, 1 Mar 2023 15:34:28 +0100 Subject: [PATCH 27/30] Bump version from 3.1.0 to 3.2.0 --- CHANGELOG.md | 4 ++++ Gemfile.lock | 2 +- lib/modularity/version.rb | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e4e865..cfc0ab3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Compatible changes +## 3.2.0 - 2023-03-01 + +### Compatible changes + - Add support for Ruby 3.2 diff --git a/Gemfile.lock b/Gemfile.lock index fd170f6..457c50d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - modularity (3.1.0) + modularity (3.2.0) GEM remote: http://rubygems.org/ diff --git a/lib/modularity/version.rb b/lib/modularity/version.rb index 7fcb430..d40bd34 100644 --- a/lib/modularity/version.rb +++ b/lib/modularity/version.rb @@ -1,3 +1,3 @@ module Modularity - VERSION = '3.1.0' + VERSION = '3.2.0' end From 5fa550c46a3ec5a90368a3a8748faa6a1bd93890 Mon Sep 17 00:00:00 2001 From: Dennis Schreiner Date: Fri, 6 Dec 2024 13:15:06 +0100 Subject: [PATCH 28/30] Add support for Ruby 3.3 --- .github/workflows/test.yml | 2 ++ CHANGELOG.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 79e2a05..f39a97e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,6 +26,8 @@ jobs: gemfile: Gemfile - ruby: 3.2.1 gemfile: Gemfile + - ruby: 3.3.6 + gemfile: Gemfile env: BUNDLE_GEMFILE: "${{ matrix.gemfile }}" steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index cfc0ab3..c4a6ad8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Compatible changes +- Add support for Ruby 3.3 + ## 3.2.0 - 2023-03-01 ### Compatible changes From 04b4abf48f9d2e2a414681683f2229935b00af08 Mon Sep 17 00:00:00 2001 From: Dennis Schreiner Date: Fri, 14 Feb 2025 15:45:11 +0100 Subject: [PATCH 29/30] Add support for Ruby 3.4 --- .github/workflows/test.yml | 4 +++- CHANGELOG.md | 1 + Gemfile.lock | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f39a97e..ca4ed8f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,6 +28,8 @@ jobs: gemfile: Gemfile - ruby: 3.3.6 gemfile: Gemfile + - ruby: 3.4.1 + gemfile: Gemfile env: BUNDLE_GEMFILE: "${{ matrix.gemfile }}" steps: @@ -38,7 +40,7 @@ jobs: ruby-version: "${{ matrix.ruby }}" - name: Bundle run: | - gem install bundler:2.2.22 + gem install bundler:2.3.27 bundle install --no-deployment - name: Run tests run: bundle exec rspec diff --git a/CHANGELOG.md b/CHANGELOG.md index c4a6ad8..908d6e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Compatible changes - Add support for Ruby 3.3 +- Add support for Ruby 3.4 ## 3.2.0 - 2023-03-01 diff --git a/Gemfile.lock b/Gemfile.lock index 457c50d..28e2709 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -44,4 +44,4 @@ DEPENDENCIES rspec BUNDLED WITH - 2.2.32 + 2.3.27 From 7117cba238a3914be9a50eea55220728806d0ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=B6ler?= Date: Thu, 15 May 2025 11:52:23 +0200 Subject: [PATCH 30/30] Update Github Actions runner image --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ca4ed8f..ffce818 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,7 +9,7 @@ name: Tests - master jobs: test: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: