Skip to content

Commit

Permalink
Add support for subcommands to the help command.
Browse files Browse the repository at this point in the history
  • Loading branch information
tristandunn committed Aug 20, 2024
1 parent be45b32 commit 027a98b
Show file tree
Hide file tree
Showing 20 changed files with 407 additions and 30 deletions.
5 changes: 3 additions & 2 deletions app/assets/stylesheets/application.tailwind.css
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@
}

#messages .message-alias td,
#messages .message-help td {
#messages .message-help td,
#messages .message-help th {
@apply py-2 px-4 font-normal text-left border-0 bg-inherit;
}

Expand Down Expand Up @@ -151,7 +152,7 @@
}

#messages .message-alias td[colspan="2"],
#messages .message-help td[colspan="3"] {
#messages .message-help th {
@apply font-sans font-bold text-center bg-slate-200;
}

Expand Down
28 changes: 26 additions & 2 deletions app/services/commands/help.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,37 @@

module Commands
class Help < Base
argument name: 0

private

# Return the command name with forward slashes removed.
#
# @return [String]
def name
@name ||= parameters[:name].to_s.tr("/", "")
end

# Return the handler for a successful command execution.
#
# @return [Success]
# @return [Command] When a valid command name is provided.
# @return [List] When no command name is provided.
def success
Success.new
if name.present?
Command.new(name: name)
else
List.new
end
end

# Validate a command when present.
#
# @return [InvalidCommand] If the command is invalid.
# @return [nil] If the command is blank or valid.
def validate_name
if name.present? && !I18n.exists?("commands.help.commands.#{name}")
InvalidCommand.new(name: name)
end
end
end
end
65 changes: 65 additions & 0 deletions app/services/commands/help/command.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# frozen_string_literal: true

module Commands
class Help < Base
class Command < Result
locals :commands

# Initialize a help command result.
#
# @return [void]
def initialize(name:)
@name = name
end

private

attr_reader :name

# Return help for the single command.
#
# @return [Array]
def command
[I18n.t(key).merge(name: name)]
end

# Return help for the subcommands or the command itself.
#
# @return [Array]
def commands
subcommands || command
end

# Return the I18n key for the command name.
#
# @return [String]
def key
"commands.help.commands.#{name}"
end

# Return the help list partial path.
#
# @return [String]
def partial
"commands/help/list"
end

# Return help for the subcommands, if any.
#
# @return [Array] When subcommands exist.
# @return [nil] When subcommands do not exist.
def subcommands
if I18n.exists?("#{key}.subcommands")
I18n
.t("#{key}.subcommands")
.each.with_object([]) do |(subcommand, details), result|
result << details.merge(
arguments: "#{subcommand} #{details[:arguments]}".strip,
name: name
)
end
end
end
end
end
end
16 changes: 16 additions & 0 deletions app/services/commands/help/invalid_command.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

module Commands
class Help < Base
class InvalidCommand < Result
locals :name

# Initialize a help invalid command result.
#
# @return [void]
def initialize(name:)
@name = name
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module Commands
class Help < Base
class Success < Result
class List < Result
locals :commands

delegate :commands, to: :class
Expand Down
7 changes: 7 additions & 0 deletions app/views/commands/help/_invalid_command.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<%# locals: (name:) %>
<tr data-chat-target="message">
<td class="message-help-invalid-command"></td>
<td class="message-help-invalid-command">
<%= t(".message", name: name) %>
</td>
</tr>
2 changes: 2 additions & 0 deletions app/views/commands/help/_invalid_command.turbo_stream.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<%# locals: (name:) %>
<%= turbo_stream.append("messages", partial: "commands/help/invalid_command", locals: { name: name }) %>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
<td colspan="2" class="message-help">
<table>
<tr>
<td colspan="3"><%= t(".header") %></td>
<th colspan="2"><%= t(".command") %></td>
<th><%= t(".description") %></td>
</tr>

<% commands.each do |command| %>
Expand Down
2 changes: 2 additions & 0 deletions app/views/commands/help/_list.turbo_stream.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<%# locals: (commands:) %>
<%= turbo_stream.append("messages", partial: "commands/help/list", locals: { commands: commands }) %>
2 changes: 0 additions & 2 deletions app/views/commands/help/_success.turbo_stream.erb

This file was deleted.

25 changes: 22 additions & 3 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,20 @@ en:
help:
commands:
alias:
description: "List the available command aliases."
arguments: "(add|list|remove|show)"
description: "Manage the command aliases for your account."
subcommands:
add:
arguments: "[alias] [command]"
description: "Add a new command alias."
list:
description: "List all available command aliases."
remove:
arguments: "[alias]"
description: "Remove a command alias."
show:
arguments: "[alias]"
description: "Show a command alias."
attack:
arguments: "[target]"
description: "Attempt to attack a target."
Expand All @@ -133,6 +146,9 @@ en:
emote:
arguments: "[message]"
description: "Emote a message to the room."
help:
arguments: "[command]"
description: "Display help for commands, or a specific command."
look:
description: "Look at the room."
move:
Expand All @@ -144,8 +160,11 @@ en:
whisper:
arguments: "[name] [message]"
description: "Whisper a message to a character in the room."
success:
header: "Available Commands"
invalid_command:
message: "There is no \"%{name}\" command."
list:
command: "Command"
description: "Description"
look:
unknown: "You don't see %{article} %{target} here."
lookup:
Expand Down
57 changes: 57 additions & 0 deletions spec/features/commands/help_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,66 @@
end
end

context "with a valid command" do
let(:command) { "/help /#{name}" }
let(:name) { "alias" }

it "displays the help command message to the sender" do
send_text(command)

expect(page).to have_help_command_message
end

it "does not broadcast the message to the room" do
using_session(:nearby_character) do
sign_in_as_character create(:character, room: character.room)
end

send_text(command)

wait_for(have_help_command_message) do
using_session(:nearby_character) do
expect(page).not_to have_help_command_message
end
end
end
end

context "with an invalid command" do
let(:command) { "/help /#{name}" }
let(:name) { "fake" }

it "displays invalid command message to the sender" do
send_text(command)

expect(page).to have_invalid_command_message(command: name)
end

it "does not broadcast the message to the room" do
using_session(:nearby_character) do
sign_in_as_character create(:character, room: character.room)
end

send_text(command)

wait_for(have_invalid_command_message(command: name)) do
using_session(:nearby_character) do
expect(page).not_to have_invalid_command_message(command: name)
end
end
end
end

protected

def have_help_command_message
have_css("#messages .message-help")
end

def have_invalid_command_message(command:)
have_css(
"#messages .message-help-invalid-command",
text: t("commands.help.invalid_command.message", name: command)
)
end
end
72 changes: 72 additions & 0 deletions spec/services/commands/help/command_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# frozen_string_literal: true

require "rails_helper"

describe Commands::Help::Command, type: :service do
describe "class" do
it "inherits from command result" do
expect(described_class.superclass).to eq(Commands::Result)
end
end

describe "#locals" do
subject(:locals) { instance.locals }

let(:instance) { described_class.new(name: name) }

context "with a command without subcommands" do
let(:name) { "help" }

it "returns the command details" do
expect(locals).to eq(
commands: [
{
arguments: t("commands.help.commands.help.arguments"),
description: t("commands.help.commands.help.description"),
name: name
}
]
)
end
end

context "with a command with subcommands" do
let(:name) { "alias" }

it "returns the command details" do # rubocop:disable RSpec/ExampleLength
expect(locals).to eq(
commands: [
{
arguments: "add [alias] [command]",
description: t("commands.help.commands.alias.subcommands.add.description"),
name: "alias"
},
{
arguments: "list",
description: t("commands.help.commands.alias.subcommands.list.description"),
name: "alias"
},
{
arguments: "remove [alias]",
description: t("commands.help.commands.alias.subcommands.remove.description"),
name: "alias"
},
{
arguments: "show [alias]",
description: t("commands.help.commands.alias.subcommands.show.description"),
name: "alias"
}
]
)
end
end
end

describe "#partial" do
subject { instance.render_options[:partial] }

let(:instance) { described_class.new(name: "help") }

it { is_expected.to eq("commands/help/list") }
end
end
20 changes: 20 additions & 0 deletions spec/services/commands/help/invalid_command_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

require "rails_helper"

describe Commands::Help::InvalidCommand, type: :service do
describe "class" do
it "inherits from command result" do
expect(described_class.superclass).to eq(Commands::Result)
end
end

describe "#locals" do
subject { instance.locals }

let(:instance) { described_class.new(name: name) }
let(:name) { double }

it { is_expected.to eq(name: name) }
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require "rails_helper"

describe Commands::Help::Success, type: :service do
describe Commands::Help::List, type: :service do
describe "class" do
it { is_expected.to delegate_method(:commands).to(:class) }

Expand Down
Loading

0 comments on commit 027a98b

Please sign in to comment.