-
-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Generate channel and prepare JS file * Inject stream identifier * Generate stimulus controller from template * Only generate stimulus controller if actually using stimulus * Prepare a test helper * Clarify usage * Standardize * Correct stream_for 🤦 * update cable_ready channel generator The most important changes: add class options add tests add default values for prompts change generator name from `cable_ready_channel` to `cable_ready:channel` * remove byebug require * change channel generator to make more use of --stream-for and --stream-from * add GitHub action to actually run the tests Co-authored-by: Marco Roth <[email protected]>
- Loading branch information
1 parent
cbf3682
commit b2c7f63
Showing
11 changed files
with
354 additions
and
3 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
name: Tests | ||
|
||
on: | ||
pull_request: | ||
branches: | ||
- '*' | ||
push: | ||
branches: | ||
- master | ||
|
||
jobs: | ||
ruby_test: | ||
name: Ruby Test Action | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
ruby-version: [2.6.6, 2.7.2, '3.0'] | ||
steps: | ||
- uses: actions/checkout@master | ||
- name: Set up Ruby ${{ matrix.ruby-version }} | ||
uses: ruby/setup-ruby@v1 | ||
with: | ||
ruby-version: ${{ matrix.ruby-version }} | ||
- uses: actions/cache@v1 | ||
with: | ||
path: vendor/bundle | ||
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }} | ||
restore-keys: | | ||
${{ runner.os }}-gems- | ||
- name: Bundle install | ||
run: | | ||
gem install bundler | ||
bundle config path vendor/bundle | ||
bundle install --jobs 4 --retry 3 | ||
- name: Run ruby tests | ||
run: bundle exec rake test |
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 |
---|---|---|
|
@@ -8,3 +8,5 @@ | |
/spec/reports/ | ||
/tmp/ | ||
node_modules/ | ||
*~ | ||
.byebug_history |
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
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,10 @@ | ||
Description: | ||
Create an ActionCable channel ready for usage with CableReady | ||
|
||
Example: | ||
bin/rails generate cable_ready:channel Thing | ||
|
||
This will create: | ||
app/channels/thing_channel.rb | ||
app/javascript/channels/thing_channel.js | ||
app/javascript/controllers/thing_controller.js (Optional) |
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,71 @@ | ||
# frozen_string_literal: true | ||
|
||
class CableReady::ChannelGenerator < Rails::Generators::NamedBase | ||
source_root File.expand_path("templates", __dir__) | ||
|
||
class_option :stream_from, type: :string | ||
class_option :stream_for, type: :string | ||
class_option :stimulus, type: :boolean | ||
|
||
def check_options | ||
raise "Can't specify --stream-from and --stream-for at the same time" if options.key?(:stream_from) && options.key?(:stream_for) | ||
end | ||
|
||
def create_channel | ||
generate "channel", file_name | ||
end | ||
|
||
def enhance_channels | ||
if using_broadcast_to? | ||
gsub_file "app/channels/#{file_name}_channel.rb", /# stream_from.*\n/, "stream_for #{resource}.find(params[:id])\n" | ||
template "app/javascript/controllers/%file_name%_controller.js" if using_stimulus? | ||
else | ||
prepend_to_file "app/javascript/channels/#{file_name}_channel.js", "import CableReady from 'cable_ready'\n" | ||
inject_into_file "app/javascript/channels/#{file_name}_channel.js", after: "// Called when there's incoming data on the websocket for this channel\n" do | ||
<<-JS | ||
if (data.cableReady) CableReady.perform(data.operations) | ||
JS | ||
end | ||
|
||
gsub_file "app/channels/#{file_name}_channel.rb", /# stream_from.*\n/, "stream_from \"#{identifier}\"\n" | ||
end | ||
end | ||
|
||
private | ||
|
||
def option_given? | ||
options.key?(:stream_from) || options.key?(:stream_for) | ||
end | ||
|
||
def using_broadcast_to? | ||
@using_broadcast_to ||= option_given? ? options.key?(:stream_for) : yes?("Are you streaming to a resource using broadcast_to? (y/N)") | ||
end | ||
|
||
def using_stimulus? | ||
@using_stimulus ||= options.fetch(:stimulus) { | ||
yes?("Are you going to use a Stimulus controller to subscribe to this channel? (y/N)") | ||
} | ||
end | ||
|
||
def resource | ||
return @resource if @resource | ||
|
||
stream_for = options.fetch(:stream_for) { | ||
ask("Which resource are you streaming for?", default: class_name) | ||
} | ||
|
||
stream_for = file_name if stream_for == "stream_for" | ||
@resource = stream_for.camelize | ||
end | ||
|
||
def identifier | ||
return @identifier if @identifier | ||
|
||
stream_from = options.fetch(:stream_from) { | ||
ask("What is the stream identifier that goes into stream_from?", default: file_name) | ||
} | ||
|
||
stream_from = file_name if stream_from == "stream_from" | ||
@identifier = stream_from.underscore | ||
end | ||
end |
21 changes: 21 additions & 0 deletions
21
lib/generators/cable_ready/templates/app/javascript/controllers/%file_name%_controller.js.tt
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,21 @@ | ||
import { Controller } from 'stimulus' | ||
import CableReady from 'cable_ready' | ||
|
||
export default class extends Controller { | ||
static values = { id: Number } | ||
|
||
connect() { | ||
this.channel = this.application.consumer.subscriptions.create({ | ||
channel: '<%= class_name %>Channel', | ||
id: this.idValue | ||
}, { | ||
received (data) { | ||
if (data.cableReady) CableReady.perform(data.operations) | ||
} | ||
}) | ||
} | ||
|
||
disconnect() { | ||
this.channel.unsubscribe() | ||
} | ||
} |
157 changes: 157 additions & 0 deletions
157
test/lib/generators/cable_ready/channel_generator_test.rb
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,157 @@ | ||
# frozen_string_literal: true | ||
|
||
require "test_helper" | ||
require "generators/cable_ready/channel_generator" | ||
|
||
class CableReady::ChannelGeneratorTest < Rails::Generators::TestCase | ||
include ::GeneratorTestHelpers | ||
|
||
tests CableReady::ChannelGenerator | ||
destination File.expand_path("../../../../tmp/dummy", __dir__) | ||
|
||
prepare_destination | ||
create_sample_app | ||
|
||
MiniTest.after_run do | ||
remove_sample_app | ||
end | ||
|
||
test "should generate channel with the same resource name and stimulus controller" do | ||
run_generator ["user", "--stream-for=user", "--stimulus"] | ||
|
||
assert_file "app/channels/user_channel.rb" do |content| | ||
assert_match(/class\ UserChannel\ </, content) | ||
assert_match(/stream_for\ User\.find\(params\[:id\]\)/, content) | ||
end | ||
|
||
assert_file "app/javascript/channels/user_channel.js", /"UserChannel"/ | ||
assert_file "app/javascript/controllers/user_controller.js", /'UserChannel'/ | ||
end | ||
|
||
test "should generate channel with different resource name" do | ||
run_generator ["my_name", "--stream-for=under_scored_resource_name", "--no-stimulus"] | ||
|
||
assert_file "app/channels/my_name_channel.rb" do |content| | ||
assert_match(/class\ MyNameChannel\ </, content) | ||
assert_match(/stream_for\ UnderScoredResourceName\.find\(params\[:id\]\)/, content) | ||
end | ||
|
||
assert_file "app/javascript/channels/my_name_channel.js", /"MyNameChannel"/ | ||
assert_no_file "app/javascript/controllers/my_name_controller.js" | ||
end | ||
|
||
test "should not generate stimulus controller if not requested" do | ||
run_generator ["comment", "--stream-for=comment", "--no-stimulus"] | ||
|
||
assert_file "app/channels/comment_channel.rb" | ||
assert_file "app/javascript/channels/comment_channel.js" | ||
assert_no_file "app/javascript/controllers/comment_controller.js" | ||
end | ||
|
||
test "should run the generator when streaming from identifier" do | ||
run_generator ["page", "--stream-from=page"] | ||
|
||
assert_file "app/channels/page_channel.rb" do |content| | ||
assert_match(/PageChannel/, content) | ||
assert_match(/stream_from\ "page"/, content) | ||
end | ||
|
||
assert_file "app/javascript/channels/page_channel.js" do |content| | ||
assert_match(/"PageChannel"/, content) | ||
assert_match(/import\ CableReady/, content) | ||
assert_match(/if\ \(data\.cableReady\)\ CableReady\.perform\(data\.operations\)/, content) | ||
end | ||
end | ||
|
||
test "should run the generator when streaming without resource and different identifier" do | ||
run_generator ["my_page", "--stream-from=ThisIsMyPage"] | ||
|
||
assert_file "app/channels/my_page_channel.rb" do |content| | ||
assert_match(/MyPageChannel/, content) | ||
assert_match(/stream_from\ "this_is_my_page"/, content) | ||
end | ||
|
||
assert_file "app/javascript/channels/my_page_channel.js" do |content| | ||
assert_match(/"MyPageChannel"/, content) | ||
assert_match(/import\ CableReady/, content) | ||
assert_match(/if\ \(data\.cableReady\)\ CableReady\.perform\(data\.operations\)/, content) | ||
end | ||
end | ||
|
||
test "should run the generator and use the NAME for --stream-from if nothing passed" do | ||
run_generator ["house", "--stream-from"] | ||
|
||
assert_file "app/channels/house_channel.rb" do |content| | ||
assert_match(/HouseChannel/, content) | ||
assert_match(/stream_from\ "house"/, content) | ||
end | ||
|
||
assert_file "app/javascript/channels/house_channel.js" do |content| | ||
assert_match(/"HouseChannel"/, content) | ||
assert_match(/import\ CableReady/, content) | ||
assert_match(/if\ \(data\.cableReady\)\ CableReady\.perform\(data\.operations\)/, content) | ||
end | ||
end | ||
|
||
test "should run the generator and use the NAME for --stream-for if nothing passed" do | ||
run_generator ["option", "--stream-for", "--stimulus"] | ||
|
||
assert_file "app/channels/option_channel.rb" do |content| | ||
assert_match(/class\ OptionChannel\ </, content) | ||
assert_match(/stream_for\ Option\.find\(params\[:id\]\)/, content) | ||
end | ||
|
||
assert_file "app/javascript/channels/option_channel.js", /"OptionChannel"/ | ||
assert_file "app/javascript/controllers/option_controller.js", /'OptionChannel'/ | ||
end | ||
|
||
test "should run not generate anything if passed stream_from and stream_for" do | ||
assert_raises "Can't specify --stream-from and --stream-for at the same time" do | ||
run_generator ["error", "--stream-from=1", "--stream-for=2"] | ||
end | ||
end | ||
|
||
# some tests without generator options to simulate the inputs passed via cli | ||
|
||
test "should generate channel with the same resource name and stimulus controller (without options)" do | ||
CableReady::ChannelGenerator.any_instance.stubs(:using_broadcast_to?).returns(true) | ||
CableReady::ChannelGenerator.any_instance.stubs(:resource).returns("Post") | ||
CableReady::ChannelGenerator.any_instance.stubs(:using_stimulus?).returns(true) | ||
|
||
run_generator ["post"] | ||
|
||
assert_file "app/channels/post_channel.rb" do |content| | ||
assert_match(/class\ PostChannel\ </, content) | ||
assert_match(/stream_for\ Post\.find\(params\[:id\]\)/, content) | ||
end | ||
|
||
assert_file "app/javascript/channels/post_channel.js", /PostChannel/ | ||
assert_file "app/javascript/controllers/post_controller.js", /'PostChannel'/ | ||
end | ||
|
||
test "should not generate stimulus controller if not requested (without options)" do | ||
CableReady::ChannelGenerator.any_instance.stubs(:using_broadcast_to?).returns(true) | ||
CableReady::ChannelGenerator.any_instance.stubs(:resource).returns("Admin") | ||
CableReady::ChannelGenerator.any_instance.stubs(:using_stimulus?).returns(false) | ||
|
||
run_generator ["admin"] | ||
|
||
assert_file "app/channels/admin_channel.rb" | ||
assert_file "app/javascript/channels/admin_channel.js" | ||
assert_no_file "app/javascript/controllers/admin_controller.js" | ||
end | ||
|
||
test "should run the generator when streaming from identifier (without options)" do | ||
CableReady::ChannelGenerator.any_instance.stubs(:using_broadcast_to?).returns(false) | ||
CableReady::ChannelGenerator.any_instance.stubs(:identifier).returns("index_identifier") | ||
|
||
run_generator ["index"] | ||
|
||
assert_file "app/channels/index_channel.rb" do |content| | ||
assert_match(/IndexChannel/, content) | ||
assert_match(/stream_from\ "index_identifier"/, content) | ||
end | ||
|
||
assert_file "app/javascript/channels/index_channel.js", /"IndexChannel"/ | ||
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,28 @@ | ||
# frozen_string_literal: true | ||
|
||
module GeneratorTestHelpers | ||
def self.included(base) | ||
base.extend ClassMethods | ||
end | ||
|
||
module ClassMethods | ||
def sample_app_path | ||
File.expand_path("../../tmp/dummy", __dir__) | ||
end | ||
|
||
def prepare_destination | ||
FileUtils.rm_rf(sample_app_path) if Dir.exist?(sample_app_path) | ||
FileUtils.mkdir_p(sample_app_path) | ||
end | ||
|
||
def create_sample_app | ||
FileUtils.cd(sample_app_path) do | ||
system "rails new . --minimal --skip-active-record --skip-test-unit --skip-spring --skip-bundle --quiet --force" | ||
end | ||
end | ||
|
||
def remove_sample_app | ||
FileUtils.rm_rf(destination_root) | ||
end | ||
end | ||
end |
Oops, something went wrong.