much-rails 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +3 -1
- data/lib/much-rails.rb +85 -0
- data/lib/much-rails/action.rb +415 -0
- data/lib/much-rails/action/base_command_result.rb +22 -0
- data/lib/much-rails/action/base_result.rb +14 -0
- data/lib/much-rails/action/base_router.rb +474 -0
- data/lib/much-rails/action/controller.rb +100 -0
- data/lib/much-rails/action/head_result.rb +18 -0
- data/lib/much-rails/action/redirect_to_result.rb +18 -0
- data/lib/much-rails/action/render_result.rb +25 -0
- data/lib/much-rails/action/router.rb +101 -0
- data/lib/much-rails/action/send_data_result.rb +18 -0
- data/lib/much-rails/action/send_file_result.rb +18 -0
- data/lib/much-rails/action/unprocessable_entity_result.rb +37 -0
- data/lib/much-rails/assets.rb +54 -0
- data/lib/much-rails/boolean.rb +7 -0
- data/lib/much-rails/call_method.rb +27 -0
- data/lib/much-rails/call_method_callbacks.rb +122 -0
- data/lib/much-rails/change_action.rb +83 -0
- data/lib/much-rails/change_action_result.rb +59 -0
- data/lib/much-rails/config.rb +55 -0
- data/lib/much-rails/date.rb +50 -0
- data/lib/much-rails/decimal.rb +7 -0
- data/lib/much-rails/destroy_action.rb +32 -0
- data/lib/much-rails/destroy_service.rb +67 -0
- data/lib/much-rails/has_slug.rb +7 -0
- data/lib/much-rails/input_value.rb +19 -0
- data/lib/much-rails/json.rb +29 -0
- data/lib/much-rails/layout.rb +142 -0
- data/lib/much-rails/layout/helper.rb +25 -0
- data/lib/much-rails/mixin.rb +7 -0
- data/lib/much-rails/not_given.rb +7 -0
- data/lib/much-rails/rails_routes.rb +29 -0
- data/lib/much-rails/railtie.rb +39 -0
- data/lib/much-rails/records.rb +5 -0
- data/lib/much-rails/records/always_destroyable.rb +30 -0
- data/lib/much-rails/records/not_destroyable.rb +30 -0
- data/lib/much-rails/records/validate_destroy.rb +92 -0
- data/lib/much-rails/result.rb +7 -0
- data/lib/much-rails/save_action.rb +32 -0
- data/lib/much-rails/save_service.rb +68 -0
- data/lib/much-rails/service.rb +18 -0
- data/lib/much-rails/service_validation_errors.rb +41 -0
- data/lib/much-rails/time.rb +28 -0
- data/lib/much-rails/version.rb +3 -1
- data/lib/much-rails/view_models.rb +3 -0
- data/lib/much-rails/view_models/breadcrumb.rb +11 -0
- data/lib/much-rails/wrap_and_call_method.rb +41 -0
- data/lib/much-rails/wrap_method.rb +45 -0
- data/much-rails.gemspec +20 -4
- data/test/helper.rb +20 -2
- data/test/support/actions/show.rb +11 -0
- data/test/support/config/routes/test.rb +3 -0
- data/test/support/factory.rb +2 -0
- data/test/support/fake_action_controller.rb +63 -0
- data/test/unit/action/base_command_result_tests.rb +43 -0
- data/test/unit/action/base_result_tests.rb +22 -0
- data/test/unit/action/base_router_tests.rb +530 -0
- data/test/unit/action/controller_tests.rb +110 -0
- data/test/unit/action/head_result_tests.rb +24 -0
- data/test/unit/action/redirect_to_result_tests.rb +24 -0
- data/test/unit/action/render_result_tests.rb +43 -0
- data/test/unit/action/router_tests.rb +252 -0
- data/test/unit/action/send_data_result_tests.rb +24 -0
- data/test/unit/action/send_file_result_tests.rb +24 -0
- data/test/unit/action/unprocessable_entity_result_tests.rb +51 -0
- data/test/unit/action_tests.rb +400 -0
- data/test/unit/assets_tests.rb +127 -0
- data/test/unit/boolean_tests.rb +17 -0
- data/test/unit/call_method_callbacks_tests.rb +176 -0
- data/test/unit/call_method_tests.rb +62 -0
- data/test/unit/change_action_result_tests.rb +113 -0
- data/test/unit/change_action_tests.rb +260 -0
- data/test/unit/config_tests.rb +68 -0
- data/test/unit/date_tests.rb +55 -0
- data/test/unit/decimal_tests.rb +17 -0
- data/test/unit/destroy_action_tests.rb +83 -0
- data/test/unit/destroy_service_tests.rb +238 -0
- data/test/unit/has_slug_tests.rb +17 -0
- data/test/unit/input_value_tests.rb +34 -0
- data/test/unit/json_tests.rb +55 -0
- data/test/unit/layout_tests.rb +155 -0
- data/test/unit/mixin_tests.rb +17 -0
- data/test/unit/much-rails_tests.rb +82 -4
- data/test/unit/not_given_tests.rb +17 -0
- data/test/unit/rails_routes_tests.rb +28 -0
- data/test/unit/records/always_destroyable_tests.rb +43 -0
- data/test/unit/records/not_destroyable_tests.rb +40 -0
- data/test/unit/records/validate_destroy_tests.rb +252 -0
- data/test/unit/result_tests.rb +17 -0
- data/test/unit/save_action_tests.rb +83 -0
- data/test/unit/save_service_tests.rb +264 -0
- data/test/unit/service_tests.rb +33 -0
- data/test/unit/service_validation_errors_tests.rb +107 -0
- data/test/unit/time_tests.rb +58 -0
- data/test/unit/view_models/breadcrumb_tests.rb +53 -0
- data/test/unit/wrap_and_call_method_tests.rb +163 -0
- data/test/unit/wrap_method_tests.rb +112 -0
- metadata +356 -7
- data/test/unit/.keep +0 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails"
|
4
|
+
|
5
|
+
module MuchRails; end
|
6
|
+
|
7
|
+
module MuchRails::Time
|
8
|
+
InvalidError = Class.new(TypeError)
|
9
|
+
|
10
|
+
# @example
|
11
|
+
# MuchRails::Time(nil) # => nil
|
12
|
+
# MuchRails::Time(" ") # => nil
|
13
|
+
# MuchRails::Time(Time.current) # => Time
|
14
|
+
# MuchRails::Time(DateTime.current) # => Time
|
15
|
+
# MuchRails::Time(Date.zone.today) # => Time
|
16
|
+
# MuchRails::Time("2020-07-04T08:15:00Z") # => Time
|
17
|
+
def self.for(value)
|
18
|
+
return if value.blank?
|
19
|
+
|
20
|
+
if value.respond_to?(:to_time) && !value.is_a?(::String)
|
21
|
+
value.to_time.utc
|
22
|
+
else
|
23
|
+
::Time.iso8601(value.to_s).utc
|
24
|
+
end
|
25
|
+
rescue
|
26
|
+
raise MuchRails::Time::InvalidError, "Invalid Time: #{value.inspect}."
|
27
|
+
end
|
28
|
+
end
|
data/lib/much-rails/version.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/call_method"
|
4
|
+
require "much-rails/mixin"
|
5
|
+
require "much-rails/result"
|
6
|
+
require "much-rails/wrap_method"
|
7
|
+
|
8
|
+
module MuchRails; end
|
9
|
+
|
10
|
+
# MuchRails::WrapAndCallMethod is a mix-in to implement the `wrap_and_call`
|
11
|
+
# and `wrap_and_map_call` class/instance method pattern.
|
12
|
+
module MuchRails::WrapAndCallMethod
|
13
|
+
include MuchRails::Mixin
|
14
|
+
|
15
|
+
mixin_included do
|
16
|
+
include MuchRails::CallMethod
|
17
|
+
include MuchRails::WrapMethod
|
18
|
+
end
|
19
|
+
|
20
|
+
mixin_class_methods do
|
21
|
+
def wrap_and_call(objects, *args)
|
22
|
+
wrap(objects, *args).each(&:call)
|
23
|
+
end
|
24
|
+
|
25
|
+
def wrap_and_map_call(objects, *args)
|
26
|
+
wrap(objects, *args).map(&:call)
|
27
|
+
end
|
28
|
+
|
29
|
+
def wrap_and_capture_call(objects, *args, capturing_result:, **kargs)
|
30
|
+
capturing_result.capture_for_all(
|
31
|
+
wrap_and_map_call(objects, *args, **kargs),
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def wrap_and_capture_call!(objects, *args, capturing_result:, **kargs)
|
36
|
+
capturing_result.capture_for_all!(
|
37
|
+
wrap_and_map_call(objects, *args, **kargs),
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/config"
|
4
|
+
require "much-rails/mixin"
|
5
|
+
|
6
|
+
module MuchRails; end
|
7
|
+
|
8
|
+
# MuchRails::WrapMethod is a mix-in to implement the `wrap` class/instance
|
9
|
+
# method pattern used in service objects, etc.
|
10
|
+
module MuchRails::WrapMethod
|
11
|
+
include MuchRails::Mixin
|
12
|
+
|
13
|
+
mixin_included do
|
14
|
+
include MuchRails::Config
|
15
|
+
|
16
|
+
add_config :wrap_method
|
17
|
+
end
|
18
|
+
|
19
|
+
mixin_class_methods do
|
20
|
+
def wrap(objects, *args)
|
21
|
+
Array.wrap(objects).map do |object|
|
22
|
+
public_send(wrap_initializer_method, object, *args)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def wrap_with_index(objects, **kargs)
|
27
|
+
Array.wrap(objects).each_with_index.map do |object, index|
|
28
|
+
public_send(wrap_initializer_method, object, index: index, **kargs)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def wrap_initializer_method(value = nil)
|
33
|
+
wrap_method_config.wrap_initializer_method = value if value
|
34
|
+
wrap_method_config.wrap_initializer_method
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class WrapMethodConfig
|
39
|
+
attr_accessor :wrap_initializer_method
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
@wrap_initializer_method = :new
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/much-rails.gemspec
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
lib = File.expand_path("lib", __dir__)
|
3
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
6
|
require "much-rails/version"
|
5
7
|
|
@@ -13,14 +15,28 @@ Gem::Specification.new do |gem|
|
|
13
15
|
gem.homepage = "https://github.com/redding/much-rails"
|
14
16
|
gem.license = "MIT"
|
15
17
|
|
16
|
-
gem.files
|
18
|
+
gem.files = `git ls-files | grep "^[^.]"`.split($INPUT_RECORD_SEPARATOR)
|
19
|
+
|
17
20
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
21
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
22
|
gem.require_paths = ["lib"]
|
20
23
|
|
21
24
|
gem.required_ruby_version = "~> 2.5"
|
22
25
|
|
23
|
-
gem.add_development_dependency("
|
26
|
+
gem.add_development_dependency("much-style-guide", ["~> 0.6.0"])
|
27
|
+
gem.add_development_dependency("assert", ["~> 2.19.5"])
|
28
|
+
gem.add_development_dependency("rails", ["> 5.0", "< 7.0"])
|
24
29
|
|
25
|
-
|
30
|
+
gem.add_dependency("activerecord", ["> 5.0", "< 7.0"])
|
31
|
+
gem.add_dependency("activesupport", ["> 5.0", "< 7.0"])
|
32
|
+
gem.add_dependency("dassets", ["~> 0.15.1"])
|
33
|
+
gem.add_dependency("dassets-erubi", ["~> 0.1.1"])
|
34
|
+
gem.add_dependency("dassets-sass", ["~> 0.5.1"])
|
35
|
+
gem.add_dependency("much-boolean", ["~> 0.2.1"])
|
36
|
+
gem.add_dependency("much-decimal", ["~> 0.1.3"])
|
37
|
+
gem.add_dependency("much-mixin", ["~> 0.2.4"])
|
38
|
+
gem.add_dependency("much-not-given", ["~> 0.1.2"])
|
39
|
+
gem.add_dependency("much-result", ["~> 0.1.3"])
|
40
|
+
gem.add_dependency("much-slug", ["~> 0.1.1"])
|
41
|
+
gem.add_dependency("oj", ["~> 3.10"])
|
26
42
|
end
|
data/test/helper.rb
CHANGED
@@ -1,12 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# this file is automatically required when you run `assert`
|
2
4
|
# put any test helpers here
|
3
5
|
|
4
6
|
# add the root dir to the load path
|
5
|
-
$LOAD_PATH.unshift(File.expand_path("
|
7
|
+
$LOAD_PATH.unshift(File.expand_path("..", __dir__))
|
8
|
+
TEST_SUPPORT_PATH = File.expand_path("support", __dir__)
|
6
9
|
|
7
10
|
# require pry for debugging (`binding.pry`)
|
8
11
|
require "pry"
|
9
12
|
|
10
13
|
require "test/support/factory"
|
11
14
|
|
12
|
-
|
15
|
+
ENV["RAILS_ENV"] ||= "test"
|
16
|
+
|
17
|
+
require "rails"
|
18
|
+
require "action_mailer/railtie"
|
19
|
+
|
20
|
+
module TestRails
|
21
|
+
class Application < Rails::Application
|
22
|
+
# Initialize configuration defaults for originally generated Rails version.
|
23
|
+
config.load_defaults 6.1
|
24
|
+
|
25
|
+
config.eager_load = false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Initialize the Rails application.
|
30
|
+
Rails.application.initialize!
|
data/test/support/factory.rb
CHANGED
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/mixin"
|
4
|
+
|
5
|
+
module FakeActionController
|
6
|
+
include MuchRails::Mixin
|
7
|
+
|
8
|
+
after_mixin_included do
|
9
|
+
include MuchRails::Action::Controller
|
10
|
+
|
11
|
+
attr_reader :params
|
12
|
+
attr_reader :head_called_with, :render_called_with
|
13
|
+
end
|
14
|
+
|
15
|
+
mixin_class_methods do
|
16
|
+
def before_action(method_name, **)
|
17
|
+
before_actions << method_name
|
18
|
+
end
|
19
|
+
|
20
|
+
def before_actions
|
21
|
+
@before_actions ||= []
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
mixin_instance_methods do
|
26
|
+
def initialize(params)
|
27
|
+
@params = FakeParams.new(params)
|
28
|
+
self.class.before_actions.each do |before_action|
|
29
|
+
public_send(before_action)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def head(*args)
|
34
|
+
@head_called_with = args
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def render(**kargs)
|
39
|
+
@render_called_with = kargs
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class FakeParams
|
44
|
+
def initialize(params)
|
45
|
+
@params = params
|
46
|
+
end
|
47
|
+
|
48
|
+
def permit!
|
49
|
+
@permit_called = true
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def [](key)
|
54
|
+
@params[key]
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_h
|
58
|
+
raise "params haven't been permitted" unless @permit_called
|
59
|
+
|
60
|
+
@params
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "assert"
|
4
|
+
require "much-rails/action/base_command_result"
|
5
|
+
|
6
|
+
class MuchRails::Action::BaseCommandResult
|
7
|
+
class UnitTests < Assert::Context
|
8
|
+
desc "MuchRails::Action::BaseCommandResult"
|
9
|
+
subject{ unit_class }
|
10
|
+
|
11
|
+
let(:unit_class){ MuchRails::Action::BaseCommandResult }
|
12
|
+
end
|
13
|
+
|
14
|
+
class InitTests < UnitTests
|
15
|
+
desc "when init"
|
16
|
+
subject do
|
17
|
+
unit_class.new(
|
18
|
+
:do_something,
|
19
|
+
"VALUE",
|
20
|
+
other_value: "OTHER VALUE",
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:controller1){ FakeController.new }
|
25
|
+
|
26
|
+
should have_readers :command_name, :command_args
|
27
|
+
|
28
|
+
should "know its attributes" do
|
29
|
+
assert_that(subject.command_name).equals(:do_something)
|
30
|
+
assert_that(subject.command_args)
|
31
|
+
.equals(["VALUE", { other_value: "OTHER VALUE" }])
|
32
|
+
|
33
|
+
assert_that(controller1.instance_exec(subject, &subject.execute_block))
|
34
|
+
.equals(value: "VALUE", other_value: "OTHER VALUE")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class FakeController
|
39
|
+
def do_something(value, other_value:)
|
40
|
+
{ value: value, other_value: other_value }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "assert"
|
4
|
+
require "much-rails/action/base_result"
|
5
|
+
|
6
|
+
class MuchRails::Action::BaseResult
|
7
|
+
class UnitTests < Assert::Context
|
8
|
+
desc "MuchRails::Action::BaseResult"
|
9
|
+
subject{ unit_class }
|
10
|
+
|
11
|
+
let(:unit_class){ MuchRails::Action::BaseResult }
|
12
|
+
end
|
13
|
+
|
14
|
+
class InitTests < UnitTests
|
15
|
+
desc "when init"
|
16
|
+
subject{ unit_class.new }
|
17
|
+
|
18
|
+
should "not implement its #execute_block method" do
|
19
|
+
assert_that{ subject.execute_block }.raises(NotImplementedError)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,530 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "assert"
|
4
|
+
require "much-rails/action/base_router"
|
5
|
+
|
6
|
+
class MuchRails::Action::BaseRouter
|
7
|
+
class UnitTests < Assert::Context
|
8
|
+
desc "MuchRails::Action::BaseRouter"
|
9
|
+
subject{ unit_class }
|
10
|
+
|
11
|
+
let(:unit_class){ MuchRails::Action::BaseRouter }
|
12
|
+
|
13
|
+
let(:caller1){ ["TEST CALLER 1"] }
|
14
|
+
|
15
|
+
should have_imeths :url_class
|
16
|
+
|
17
|
+
should "know its constants" do
|
18
|
+
assert_that(subject::DEFAULT_BASE_URL).equals("/")
|
19
|
+
assert_that(subject.url_class).equals(unit_class::BaseURL)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class InitTests < UnitTests
|
24
|
+
desc "when init"
|
25
|
+
subject{ unit_class.new }
|
26
|
+
|
27
|
+
setup do
|
28
|
+
Assert.stub_tap_on_call(unit_class::RequestTypeSet, :new) do |set, _|
|
29
|
+
Assert.stub_tap_on_call(set, :add) do |_, call|
|
30
|
+
@request_type_set_add_call = call
|
31
|
+
end
|
32
|
+
end
|
33
|
+
Assert.stub_tap_on_call(unit_class::URLSet, :new) do |set, call|
|
34
|
+
@url_set_new_call = call
|
35
|
+
Assert.stub_on_call(set, :path_for) do |call|
|
36
|
+
@url_set_path_for_call = call
|
37
|
+
"TEST PATH STRING"
|
38
|
+
end
|
39
|
+
Assert.stub_on_call(set, :url_for) do |call|
|
40
|
+
@url_set_url_for_call = call
|
41
|
+
"TEST URL STRING"
|
42
|
+
end
|
43
|
+
Assert.stub_tap_on_call(set, :add) do |_, call|
|
44
|
+
@url_set_add_call = call
|
45
|
+
end
|
46
|
+
end
|
47
|
+
Assert.stub_tap_on_call(unit_class::Definition, :for_route) do |_, call|
|
48
|
+
@route_definition_call = call
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
should have_readers :name
|
53
|
+
should have_readers :request_type_set, :url_set, :definitions
|
54
|
+
|
55
|
+
should have_imeths :url_class, :unrouted_urls, :apply_to
|
56
|
+
should have_imeths :path_for, :url_for
|
57
|
+
should have_imeths :request_type
|
58
|
+
should have_imeths :base_url, :url
|
59
|
+
should have_imeths :get, :post, :put, :patch, :delete
|
60
|
+
|
61
|
+
should "know its default attributes" do
|
62
|
+
assert_that(subject.name).is_nil
|
63
|
+
assert_that(subject.request_type_set).is_empty
|
64
|
+
assert_that(subject.url_set).is_empty
|
65
|
+
assert_that(subject.unrouted_urls).is_empty
|
66
|
+
assert_that(subject.definitions).is_empty
|
67
|
+
assert_that(subject.base_url).equals(unit_class::DEFAULT_BASE_URL)
|
68
|
+
assert_that(subject.url_class).equals(unit_class.url_class)
|
69
|
+
|
70
|
+
assert_that(@url_set_new_call.args).equals([subject])
|
71
|
+
end
|
72
|
+
|
73
|
+
should "instance_exec any given block" do
|
74
|
+
router = unit_class.new{ base_url "/test" }
|
75
|
+
assert_that(router.base_url).equals("/test")
|
76
|
+
end
|
77
|
+
|
78
|
+
should "not implement #apply_to" do
|
79
|
+
assert_that{ subject.apply_to("TEST SCOPE") }.raises(NotImplementedError)
|
80
|
+
end
|
81
|
+
|
82
|
+
should "build path/URL strings for named URLs" do
|
83
|
+
path_string = subject.path_for(:url1, "TEST PATH ARGS")
|
84
|
+
assert_that(path_string).equals("TEST PATH STRING")
|
85
|
+
assert_that(@url_set_path_for_call.args).equals([:url1, "TEST PATH ARGS"])
|
86
|
+
|
87
|
+
url_string = subject.url_for(:url1, "TEST URL ARGS")
|
88
|
+
assert_that(url_string).equals("TEST URL STRING")
|
89
|
+
assert_that(@url_set_url_for_call.args).equals([:url1, "TEST URL ARGS"])
|
90
|
+
end
|
91
|
+
|
92
|
+
should "define request types" do
|
93
|
+
proc = ->(request){}
|
94
|
+
request_type = subject.request_type(:type1, &proc)
|
95
|
+
assert_that(subject.request_type_set).is_not_empty
|
96
|
+
assert_that(request_type).is_instance_of(unit_class::RequestType)
|
97
|
+
assert_that(@request_type_set_add_call.args).equals([:type1, proc])
|
98
|
+
end
|
99
|
+
|
100
|
+
should "define the base URL" do
|
101
|
+
subject.base_url(new_url = Factory.url)
|
102
|
+
assert_that(subject.base_url).equals(new_url)
|
103
|
+
end
|
104
|
+
|
105
|
+
should "define URLs" do
|
106
|
+
url = subject.url(:url1, path = Factory.url)
|
107
|
+
assert_that(subject.url_set).is_not_empty
|
108
|
+
assert_that(url).is_kind_of(subject.url_class)
|
109
|
+
assert_that(@url_set_add_call.args).equals([:url1, path])
|
110
|
+
assert_that(subject.unrouted_urls).equals([url])
|
111
|
+
|
112
|
+
ex =
|
113
|
+
assert_that{ subject.url(:url2.to_s, Factory.url) }
|
114
|
+
.raises(ArgumentError)
|
115
|
+
assert_that(ex.message)
|
116
|
+
.equals(
|
117
|
+
"Named URLs must be defined with Symbol names, given `\"url2\"`.",
|
118
|
+
)
|
119
|
+
|
120
|
+
ex =
|
121
|
+
assert_that{ subject.url(:url2, path = Factory.url.to_sym) }
|
122
|
+
.raises(ArgumentError)
|
123
|
+
assert_that(ex.message)
|
124
|
+
.equals(
|
125
|
+
"Named URLs must be defined with String paths, "\
|
126
|
+
"given `#{path.inspect}`.",
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
should "define HTTP method routes" do
|
131
|
+
request_type_name = Factory.symbol
|
132
|
+
request_type_proc = ->(request){}
|
133
|
+
request_type = subject.request_type(request_type_name, &request_type_proc)
|
134
|
+
request_type_class_name = Factory.string
|
135
|
+
request_type_action =
|
136
|
+
unit_class::RequestTypeAction.new(request_type, request_type_class_name)
|
137
|
+
url_name = Factory.symbol
|
138
|
+
url_path = Factory.url
|
139
|
+
url = subject.url(url_name, url_path)
|
140
|
+
default_class_name = Factory.string
|
141
|
+
|
142
|
+
definition =
|
143
|
+
subject.get(
|
144
|
+
url_name,
|
145
|
+
default_class_name,
|
146
|
+
called_from: caller1,
|
147
|
+
**{ request_type_name => request_type_class_name },
|
148
|
+
)
|
149
|
+
assert_that(subject.definitions.size).equals(1)
|
150
|
+
assert_that(definition).is_instance_of(unit_class::Definition)
|
151
|
+
assert_that(@route_definition_call.kargs)
|
152
|
+
.equals(
|
153
|
+
http_method: :get,
|
154
|
+
url: url,
|
155
|
+
default_action_class_name: default_class_name,
|
156
|
+
request_type_actions: [request_type_action],
|
157
|
+
called_from: caller1,
|
158
|
+
)
|
159
|
+
|
160
|
+
definition =
|
161
|
+
subject.post(url_name, default_class_name, called_from: caller1)
|
162
|
+
assert_that(subject.definitions.size).equals(2)
|
163
|
+
assert_that(definition).is_instance_of(unit_class::Definition)
|
164
|
+
assert_that(@route_definition_call.kargs)
|
165
|
+
.equals(
|
166
|
+
http_method: :post,
|
167
|
+
url: url,
|
168
|
+
default_action_class_name: default_class_name,
|
169
|
+
request_type_actions: [],
|
170
|
+
called_from: caller1,
|
171
|
+
)
|
172
|
+
|
173
|
+
definition =
|
174
|
+
subject.put(url_path, default_class_name, called_from: caller1)
|
175
|
+
assert_that(subject.definitions.size).equals(3)
|
176
|
+
assert_that(definition).is_instance_of(unit_class::Definition)
|
177
|
+
assert_that(@route_definition_call.kargs)
|
178
|
+
.equals(
|
179
|
+
http_method: :put,
|
180
|
+
url: subject.url_class.for(subject, url_path),
|
181
|
+
default_action_class_name: default_class_name,
|
182
|
+
request_type_actions: [],
|
183
|
+
called_from: caller1,
|
184
|
+
)
|
185
|
+
|
186
|
+
definition =
|
187
|
+
subject.patch(url_name, default_class_name, called_from: caller1)
|
188
|
+
assert_that(subject.definitions.size).equals(4)
|
189
|
+
assert_that(definition).is_instance_of(unit_class::Definition)
|
190
|
+
assert_that(@route_definition_call.kargs)
|
191
|
+
.equals(
|
192
|
+
http_method: :patch,
|
193
|
+
url: url,
|
194
|
+
default_action_class_name: default_class_name,
|
195
|
+
request_type_actions: [],
|
196
|
+
called_from: caller1,
|
197
|
+
)
|
198
|
+
|
199
|
+
definition =
|
200
|
+
subject.delete(url_name, default_class_name, called_from: caller1)
|
201
|
+
assert_that(subject.definitions.size).equals(5)
|
202
|
+
assert_that(definition).is_instance_of(unit_class::Definition)
|
203
|
+
assert_that(@route_definition_call.kargs)
|
204
|
+
.equals(
|
205
|
+
http_method: :delete,
|
206
|
+
url: url,
|
207
|
+
default_action_class_name: default_class_name,
|
208
|
+
request_type_actions: [],
|
209
|
+
called_from: caller1,
|
210
|
+
)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
class RequestTypeSetUnitTests < UnitTests
|
215
|
+
desc "RequestTypeSet"
|
216
|
+
subject{ request_type_set_class }
|
217
|
+
|
218
|
+
let(:request_type_set_class){ unit_class::RequestTypeSet }
|
219
|
+
let(:request_type_class){ unit_class::RequestType }
|
220
|
+
end
|
221
|
+
|
222
|
+
class RequestTypeSetInitTests < RequestTypeSetUnitTests
|
223
|
+
desc "when init"
|
224
|
+
subject{ request_type_set_class.new }
|
225
|
+
|
226
|
+
setup do
|
227
|
+
Assert.stub_tap_on_call(request_type_class, :new) do |_url, call|
|
228
|
+
@request_type_new_call = call
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
let(:constraints_lambda1){ ->(request){} }
|
233
|
+
|
234
|
+
should have_imeths :empty?, :add, :get
|
235
|
+
|
236
|
+
should "add request types" do
|
237
|
+
assert_that(subject).is_empty
|
238
|
+
|
239
|
+
request_type = subject.add(:type1.to_s, constraints_lambda1)
|
240
|
+
assert_that(subject).is_not_empty
|
241
|
+
assert_that(request_type).is_instance_of(request_type_class)
|
242
|
+
assert_that(@request_type_new_call.args)
|
243
|
+
.equals([:type1, constraints_lambda1])
|
244
|
+
|
245
|
+
ex =
|
246
|
+
assert_that{ subject.add(:type1, constraints_lambda1) }
|
247
|
+
.raises(ArgumentError)
|
248
|
+
assert_that(ex.message)
|
249
|
+
.equals("There is already a request type named `:type1`.")
|
250
|
+
end
|
251
|
+
|
252
|
+
should "get request types" do
|
253
|
+
ex =
|
254
|
+
assert_that{ subject.get(:type1) }.raises(ArgumentError)
|
255
|
+
assert_that(ex.message).equals("There is no request type named `:type1`.")
|
256
|
+
|
257
|
+
added_request_type = subject.add(:type1.to_s, constraints_lambda1)
|
258
|
+
request_type = subject.get(:type1)
|
259
|
+
assert_that(request_type).is(added_request_type)
|
260
|
+
|
261
|
+
request_type = subject.get(:type1)
|
262
|
+
assert_that(request_type).is(added_request_type)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
class RequestTypeUnitTests < UnitTests
|
267
|
+
desc "RequestType"
|
268
|
+
subject{ request_type_class }
|
269
|
+
|
270
|
+
let(:request_type_class){ unit_class::RequestType }
|
271
|
+
end
|
272
|
+
|
273
|
+
class RequestTypeInitTests < RequestTypeUnitTests
|
274
|
+
desc "when init"
|
275
|
+
subject{ request_type_class.new(name1, constraints_lambda1) }
|
276
|
+
|
277
|
+
let(:name1){ Factory.symbol }
|
278
|
+
let(:constraints_lambda1){ ->(request){} }
|
279
|
+
|
280
|
+
should have_imeths :name, :constraints_lambda
|
281
|
+
|
282
|
+
should "know its attributes" do
|
283
|
+
assert_that(subject.name).equals(name1)
|
284
|
+
assert_that(subject.constraints_lambda).equals(constraints_lambda1)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
class RequestTypeActionUnitTests < UnitTests
|
289
|
+
desc "RequestTypeAction"
|
290
|
+
subject{ request_type_action_class }
|
291
|
+
|
292
|
+
let(:request_type_action_class){ unit_class::RequestTypeAction }
|
293
|
+
end
|
294
|
+
|
295
|
+
class RequestTypeActionInitTests < RequestTypeActionUnitTests
|
296
|
+
desc "when init"
|
297
|
+
subject{ request_type_action_class.new(request_type1, action_class_name1) }
|
298
|
+
|
299
|
+
let(:name1){ Factory.symbol }
|
300
|
+
let(:constraints_lambda1){ ->(request){} }
|
301
|
+
let(:request_type1) do
|
302
|
+
unit_class::RequestType.new(name1, constraints_lambda1)
|
303
|
+
end
|
304
|
+
let(:action_class_name1){ Factory.string }
|
305
|
+
|
306
|
+
should have_imeths :request_type, :class_name, :constraints_lambda
|
307
|
+
|
308
|
+
should "know its attributes" do
|
309
|
+
assert_that(subject.request_type).equals(request_type1)
|
310
|
+
assert_that(subject.class_name).equals(action_class_name1)
|
311
|
+
assert_that(subject.constraints_lambda)
|
312
|
+
.equals(request_type1.constraints_lambda)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
class URLSetUnitTests < UnitTests
|
317
|
+
desc "URLSet"
|
318
|
+
subject{ url_set_class }
|
319
|
+
|
320
|
+
let(:url_set_class){ unit_class::URLSet }
|
321
|
+
end
|
322
|
+
|
323
|
+
class URLSetInitTests < URLSetUnitTests
|
324
|
+
desc "when init"
|
325
|
+
subject{ url_set_class.new(router1) }
|
326
|
+
|
327
|
+
setup do
|
328
|
+
Assert.stub_tap_on_call(router1.url_class, :new) do |url, call|
|
329
|
+
@url_new_call = call
|
330
|
+
Assert.stub_on_call(url, :path_for) do |call|
|
331
|
+
@url_path_for_call = call
|
332
|
+
"TEST PATH STRING"
|
333
|
+
end
|
334
|
+
Assert.stub_on_call(url, :url_for) do |call|
|
335
|
+
@url_url_for_call = call
|
336
|
+
"TEST URL STRING"
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
let(:router1){ unit_class.new }
|
342
|
+
|
343
|
+
should have_imeths :empty?, :urls, :add, :fetch, :path_for, :url_for
|
344
|
+
|
345
|
+
should "add URLs" do
|
346
|
+
assert_that(subject).is_empty
|
347
|
+
|
348
|
+
url = subject.add(:url1.to_s, path = Factory.url)
|
349
|
+
assert_that(subject).is_not_empty
|
350
|
+
assert_that(subject.urls).equals([url])
|
351
|
+
assert_that(url).is_kind_of(router1.url_class)
|
352
|
+
assert_that(@url_new_call.args).equals([router1, path, :url1])
|
353
|
+
|
354
|
+
ex =
|
355
|
+
assert_that{ subject.add(:url1, Factory.url) }.raises(ArgumentError)
|
356
|
+
assert_that(ex.message).equals("There is already a URL named `:url1`.")
|
357
|
+
end
|
358
|
+
|
359
|
+
should "fetch URLs" do
|
360
|
+
ex =
|
361
|
+
assert_that{ subject.fetch(:url1) }.raises(ArgumentError)
|
362
|
+
assert_that(ex.message).equals("There is no URL named `:url1`.")
|
363
|
+
assert_that(subject.fetch(:url1, "/url1")).equals("/url1")
|
364
|
+
|
365
|
+
added_url = subject.add(:url1, Factory.url)
|
366
|
+
url = subject.fetch(:url1)
|
367
|
+
assert_that(url).is(added_url)
|
368
|
+
|
369
|
+
url = subject.fetch(:url1.to_s)
|
370
|
+
assert_that(url).is(added_url)
|
371
|
+
end
|
372
|
+
|
373
|
+
should "build path/URL strings for named URLs" do
|
374
|
+
ex =
|
375
|
+
assert_that{ subject.path_for(:url1) }.raises(ArgumentError)
|
376
|
+
assert_that(ex.message).equals("There is no URL named `:url1`.")
|
377
|
+
ex =
|
378
|
+
assert_that{ subject.url_for(:url1) }.raises(ArgumentError)
|
379
|
+
assert_that(ex.message).equals("There is no URL named `:url1`.")
|
380
|
+
|
381
|
+
subject.add(:url1, Factory.url)
|
382
|
+
|
383
|
+
path_string = subject.path_for(:url1, "TEST PATH ARGS")
|
384
|
+
assert_that(path_string).equals("TEST PATH STRING")
|
385
|
+
assert_that(@url_path_for_call.args).equals(["TEST PATH ARGS"])
|
386
|
+
|
387
|
+
url_string = subject.url_for(:url1, "TEST URL ARGS")
|
388
|
+
assert_that(url_string).equals("TEST URL STRING")
|
389
|
+
assert_that(@url_url_for_call.args).equals(["TEST URL ARGS"])
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
class BaseURLUnitTests < UnitTests
|
394
|
+
desc "BaseURL"
|
395
|
+
subject{ base_url_class }
|
396
|
+
|
397
|
+
let(:base_url_class){ unit_class::BaseURL }
|
398
|
+
|
399
|
+
let(:router1){ unit_class.new }
|
400
|
+
let(:url_path1){ Factory.url }
|
401
|
+
let(:url_name1){ Factory.symbol }
|
402
|
+
|
403
|
+
should have_imeths :url_name, :url_path, :for
|
404
|
+
|
405
|
+
should "know its URL name" do
|
406
|
+
assert_that(subject.url_name(nil, nil)).is_nil
|
407
|
+
assert_that(subject.url_name(router1, nil)).is_nil
|
408
|
+
assert_that(subject.url_name(nil, url_name1)).equals(url_name1)
|
409
|
+
assert_that(subject.url_name(router1, url_name1)).equals(url_name1)
|
410
|
+
|
411
|
+
router_name = Factory.symbol
|
412
|
+
Assert.stub(router1, :name){ router_name }
|
413
|
+
assert_that(subject.url_name(router1, url_name1))
|
414
|
+
.equals("#{router_name}_#{url_name1}".to_sym)
|
415
|
+
end
|
416
|
+
|
417
|
+
should "know its URL path" do
|
418
|
+
assert_that(subject.url_path(nil, nil)).is_nil
|
419
|
+
assert_that(subject.url_path(router1, nil)).is_nil
|
420
|
+
assert_that(subject.url_path(nil, url_path1)).equals(url_path1)
|
421
|
+
assert_that(subject.url_path(router1, url_path1)).equals(url_path1)
|
422
|
+
|
423
|
+
router_base_url = Factory.url
|
424
|
+
Assert.stub(router1, :base_url){ router_base_url }
|
425
|
+
assert_that(subject.url_path(router1, url_path1))
|
426
|
+
.equals(File.join(router_base_url, url_path1))
|
427
|
+
end
|
428
|
+
|
429
|
+
should "build URLs from an existing URL or a path string" do
|
430
|
+
url1 = base_url_class.new(router1, url_path1, url_name1)
|
431
|
+
|
432
|
+
url = base_url_class.for(router1, url1)
|
433
|
+
assert_that(url).is(url1)
|
434
|
+
|
435
|
+
url = base_url_class.for(router1, url_path1)
|
436
|
+
assert_that(url.path).equals(url1.path)
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
class BaseURLInitTests < BaseURLUnitTests
|
441
|
+
desc "when init"
|
442
|
+
subject{ base_url_class.new(router1, url_path1, url_name1) }
|
443
|
+
|
444
|
+
should have_readers :router, :url_path, :url_name
|
445
|
+
should have_imeths :name, :path, :path_for, :url_for
|
446
|
+
|
447
|
+
should "know its attributes" do
|
448
|
+
assert_that(subject.name)
|
449
|
+
.equals(base_url_class.url_name(router1, url_name1))
|
450
|
+
assert_that(subject.path)
|
451
|
+
.equals(base_url_class.url_path(router1, url_path1))
|
452
|
+
|
453
|
+
assert_that{ subject.path_for("TEST ARGS") }.raises(NotImplementedError)
|
454
|
+
assert_that{ subject.url_for("TEST ARGS") }.raises(NotImplementedError)
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
class DefinitionUnitTests < UnitTests
|
459
|
+
desc "Definition"
|
460
|
+
subject{ definition_class }
|
461
|
+
|
462
|
+
let(:definition_class){ unit_class::Definition }
|
463
|
+
|
464
|
+
let(:router1){ unit_class.new }
|
465
|
+
let(:http_method1){ Factory.symbol }
|
466
|
+
let(:url1){ unit_class::BaseURL.for(router1, Factory.url) }
|
467
|
+
let(:url_path1){ url1.path }
|
468
|
+
let(:url_name1){ url1.name }
|
469
|
+
let(:default_action_class_name1){ Factory.string }
|
470
|
+
let(:request_type_actions1){ [] }
|
471
|
+
|
472
|
+
should have_imeths :for_route
|
473
|
+
|
474
|
+
should "build definitions given route information" do
|
475
|
+
definition1 =
|
476
|
+
definition_class.new(
|
477
|
+
http_method: http_method1,
|
478
|
+
url: url1,
|
479
|
+
default_action_class_name: default_action_class_name1,
|
480
|
+
request_type_actions: request_type_actions1,
|
481
|
+
called_from: caller1,
|
482
|
+
)
|
483
|
+
|
484
|
+
definition =
|
485
|
+
definition_class.for_route(
|
486
|
+
http_method: http_method1,
|
487
|
+
url: url1,
|
488
|
+
default_action_class_name: default_action_class_name1,
|
489
|
+
request_type_actions: request_type_actions1,
|
490
|
+
called_from: caller1,
|
491
|
+
)
|
492
|
+
assert_that(definition).equals(definition1)
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
class DefinitionInitTests < DefinitionUnitTests
|
497
|
+
desc "when init"
|
498
|
+
subject do
|
499
|
+
definition_class.new(
|
500
|
+
http_method: http_method1,
|
501
|
+
url: url1,
|
502
|
+
default_action_class_name: default_action_class_name1,
|
503
|
+
request_type_actions: request_type_actions1,
|
504
|
+
default_params: default_params1,
|
505
|
+
called_from: caller1,
|
506
|
+
)
|
507
|
+
end
|
508
|
+
|
509
|
+
let(:default_params1) do
|
510
|
+
{ Factory.string => Factory.string }
|
511
|
+
end
|
512
|
+
|
513
|
+
should have_readers :http_method, :url, :default_params
|
514
|
+
should have_readers :default_action_class_name, :request_type_actions
|
515
|
+
should have_readers :called_from
|
516
|
+
should have_imeths :path, :name, :has_default_action_class_name?
|
517
|
+
|
518
|
+
should "know its attributes" do
|
519
|
+
assert_that(subject.http_method).equals(http_method1)
|
520
|
+
assert_that(subject.url).equals(url1)
|
521
|
+
assert_that(subject.default_params).equals(default_params1)
|
522
|
+
assert_that(subject.default_action_class_name)
|
523
|
+
.equals(default_action_class_name1)
|
524
|
+
assert_that(subject.request_type_actions).equals(request_type_actions1)
|
525
|
+
assert_that(subject.called_from).equals(caller1)
|
526
|
+
assert_that(subject.path).equals(url_path1)
|
527
|
+
assert_that(subject.name).equals(url_name1)
|
528
|
+
end
|
529
|
+
end
|
530
|
+
end
|