-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add associated object generator (#23)
* Add associated object generator Run with: `bin/rails g associated Organization::Seats` Co-authored-by: Garrett Dimon <[email protected]> * Simplify our destination_root a bit * Chomp the plain method accessor test, not too sure if we need it * Reuse some of the naming methods and go through object reader * Let's leave this up to apps and their linter * Trim some of our methods we don't need now * Think this is a little clearer * Better, hm? * Tweak usage more * Surface in documentation --------- Co-authored-by: Garrett Dimon <[email protected]>
- Loading branch information
1 parent
c1d8a2c
commit deccb7f
Showing
7 changed files
with
134 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
Description: | ||
Create a PORO collaborator associated object inheriting from `ActiveRecord::AssociatedObject` that's associated with an Active Record record class. | ||
|
||
It'll be associated on the record with `has_object`. | ||
|
||
Note: associated object names support pluralized class names. So "Seats" remain "seats" in all cases, and "Seat" remains "seat" in all cases. | ||
Example: | ||
bin/rails generate associated Organization::Seats | ||
|
||
This will create: | ||
app/models/organization/seats.rb | ||
test/models/organization/seats_test.rb | ||
|
||
And in Organization, this will insert: | ||
has_object :seats |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
class AssociatedGenerator < Rails::Generators::NamedBase | ||
source_root File.expand_path("templates", __dir__) | ||
|
||
def generate_associated_object_files | ||
template "associated.rb", "app/models/#{name.underscore}.rb" | ||
template "associated_test.rb", "test/models/#{name.underscore}_test.rb" | ||
end | ||
|
||
def connect_associated_object | ||
record_file = "#{destination_root}/app/models/#{record_path}.rb" | ||
raise "Record class '#{record_klass}' does not exist" unless File.exist?(record_file) | ||
|
||
inject_into_class record_file, record_klass do | ||
optimize_indentation "has_object :#{associated_object_path}", 2 | ||
end | ||
end | ||
|
||
private | ||
|
||
# The `:name` argument can handle model names, but associated object class names aren't singularized. | ||
# So these record and associated_object methods prevent that. | ||
def record_path = record_klass.downcase.underscore | ||
def record_klass = name.deconstantize | ||
|
||
def associated_object_path = associated_object_class.downcase.underscore | ||
def associated_object_class = name.demodulize | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
class <%= name %> < ActiveRecord::AssociatedObject | ||
extension do | ||
# Extend <%= record_klass %> here | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
require "test_helper" | ||
|
||
class <%= name %>Test < ActiveSupport::TestCase | ||
setup do | ||
# @<%= record_path %> = <%= record_path.pluralize %>(:TODO_fixture_name) | ||
# @<%= associated_object_path %> = @<%= record_path %>.<%= associated_object_path %> | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
require "test_helper" | ||
require "pathname" | ||
require "rails/generators" | ||
require "generators/associated/associated_generator" | ||
|
||
class AssociatedGeneratorTest < Rails::Generators::TestCase | ||
tests AssociatedGenerator | ||
destination Pathname(__dir__).join("../../../tmp/generators") | ||
|
||
setup :prepare_destination, :create_record_file, :create_record_test_file | ||
arguments %w[Organization::Seats] | ||
|
||
test "generator runs without errors" do | ||
assert_nothing_raised { run_generator } | ||
end | ||
|
||
test "generates an object.rb file" do | ||
run_generator | ||
|
||
assert_file "app/models/organization/seats.rb", <<~RUBY | ||
class Organization::Seats < ActiveRecord::AssociatedObject | ||
extension do | ||
# Extend Organization here | ||
end | ||
end | ||
RUBY | ||
end | ||
|
||
test "generates an object_test.rb file" do | ||
run_generator | ||
|
||
assert_file "test/models/organization/seats_test.rb", /Organization::SeatsTest/ | ||
end | ||
|
||
test "connects record" do | ||
run_generator | ||
|
||
assert_file "app/models/organization.rb", <<~RUBY | ||
class Organization | ||
has_object :seats | ||
end | ||
RUBY | ||
end | ||
|
||
test "raises error if associated record doesn't exist" do | ||
assert_raise RuntimeError do | ||
run_generator ["Business::Monkey"] | ||
end | ||
end | ||
|
||
private | ||
|
||
def create_record_file | ||
create_file "app/models/organization.rb", <<~RUBY | ||
class Organization | ||
end | ||
RUBY | ||
end | ||
|
||
def create_record_test_file | ||
create_file "test/models/organization_test.rb", <<~RUBY | ||
require "test_helper" | ||
class OrganizationTest < ActiveSupport::TestCase | ||
end | ||
RUBY | ||
end | ||
|
||
def create_file(path, content) | ||
destination_root.join(path).tap { _1.dirname.mkpath }.write content | ||
end | ||
end |