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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/lib/much-rails.rb +85 -0
  4. data/lib/much-rails/action.rb +415 -0
  5. data/lib/much-rails/action/base_command_result.rb +22 -0
  6. data/lib/much-rails/action/base_result.rb +14 -0
  7. data/lib/much-rails/action/base_router.rb +474 -0
  8. data/lib/much-rails/action/controller.rb +100 -0
  9. data/lib/much-rails/action/head_result.rb +18 -0
  10. data/lib/much-rails/action/redirect_to_result.rb +18 -0
  11. data/lib/much-rails/action/render_result.rb +25 -0
  12. data/lib/much-rails/action/router.rb +101 -0
  13. data/lib/much-rails/action/send_data_result.rb +18 -0
  14. data/lib/much-rails/action/send_file_result.rb +18 -0
  15. data/lib/much-rails/action/unprocessable_entity_result.rb +37 -0
  16. data/lib/much-rails/assets.rb +54 -0
  17. data/lib/much-rails/boolean.rb +7 -0
  18. data/lib/much-rails/call_method.rb +27 -0
  19. data/lib/much-rails/call_method_callbacks.rb +122 -0
  20. data/lib/much-rails/change_action.rb +83 -0
  21. data/lib/much-rails/change_action_result.rb +59 -0
  22. data/lib/much-rails/config.rb +55 -0
  23. data/lib/much-rails/date.rb +50 -0
  24. data/lib/much-rails/decimal.rb +7 -0
  25. data/lib/much-rails/destroy_action.rb +32 -0
  26. data/lib/much-rails/destroy_service.rb +67 -0
  27. data/lib/much-rails/has_slug.rb +7 -0
  28. data/lib/much-rails/input_value.rb +19 -0
  29. data/lib/much-rails/json.rb +29 -0
  30. data/lib/much-rails/layout.rb +142 -0
  31. data/lib/much-rails/layout/helper.rb +25 -0
  32. data/lib/much-rails/mixin.rb +7 -0
  33. data/lib/much-rails/not_given.rb +7 -0
  34. data/lib/much-rails/rails_routes.rb +29 -0
  35. data/lib/much-rails/railtie.rb +39 -0
  36. data/lib/much-rails/records.rb +5 -0
  37. data/lib/much-rails/records/always_destroyable.rb +30 -0
  38. data/lib/much-rails/records/not_destroyable.rb +30 -0
  39. data/lib/much-rails/records/validate_destroy.rb +92 -0
  40. data/lib/much-rails/result.rb +7 -0
  41. data/lib/much-rails/save_action.rb +32 -0
  42. data/lib/much-rails/save_service.rb +68 -0
  43. data/lib/much-rails/service.rb +18 -0
  44. data/lib/much-rails/service_validation_errors.rb +41 -0
  45. data/lib/much-rails/time.rb +28 -0
  46. data/lib/much-rails/version.rb +3 -1
  47. data/lib/much-rails/view_models.rb +3 -0
  48. data/lib/much-rails/view_models/breadcrumb.rb +11 -0
  49. data/lib/much-rails/wrap_and_call_method.rb +41 -0
  50. data/lib/much-rails/wrap_method.rb +45 -0
  51. data/much-rails.gemspec +20 -4
  52. data/test/helper.rb +20 -2
  53. data/test/support/actions/show.rb +11 -0
  54. data/test/support/config/routes/test.rb +3 -0
  55. data/test/support/factory.rb +2 -0
  56. data/test/support/fake_action_controller.rb +63 -0
  57. data/test/unit/action/base_command_result_tests.rb +43 -0
  58. data/test/unit/action/base_result_tests.rb +22 -0
  59. data/test/unit/action/base_router_tests.rb +530 -0
  60. data/test/unit/action/controller_tests.rb +110 -0
  61. data/test/unit/action/head_result_tests.rb +24 -0
  62. data/test/unit/action/redirect_to_result_tests.rb +24 -0
  63. data/test/unit/action/render_result_tests.rb +43 -0
  64. data/test/unit/action/router_tests.rb +252 -0
  65. data/test/unit/action/send_data_result_tests.rb +24 -0
  66. data/test/unit/action/send_file_result_tests.rb +24 -0
  67. data/test/unit/action/unprocessable_entity_result_tests.rb +51 -0
  68. data/test/unit/action_tests.rb +400 -0
  69. data/test/unit/assets_tests.rb +127 -0
  70. data/test/unit/boolean_tests.rb +17 -0
  71. data/test/unit/call_method_callbacks_tests.rb +176 -0
  72. data/test/unit/call_method_tests.rb +62 -0
  73. data/test/unit/change_action_result_tests.rb +113 -0
  74. data/test/unit/change_action_tests.rb +260 -0
  75. data/test/unit/config_tests.rb +68 -0
  76. data/test/unit/date_tests.rb +55 -0
  77. data/test/unit/decimal_tests.rb +17 -0
  78. data/test/unit/destroy_action_tests.rb +83 -0
  79. data/test/unit/destroy_service_tests.rb +238 -0
  80. data/test/unit/has_slug_tests.rb +17 -0
  81. data/test/unit/input_value_tests.rb +34 -0
  82. data/test/unit/json_tests.rb +55 -0
  83. data/test/unit/layout_tests.rb +155 -0
  84. data/test/unit/mixin_tests.rb +17 -0
  85. data/test/unit/much-rails_tests.rb +82 -4
  86. data/test/unit/not_given_tests.rb +17 -0
  87. data/test/unit/rails_routes_tests.rb +28 -0
  88. data/test/unit/records/always_destroyable_tests.rb +43 -0
  89. data/test/unit/records/not_destroyable_tests.rb +40 -0
  90. data/test/unit/records/validate_destroy_tests.rb +252 -0
  91. data/test/unit/result_tests.rb +17 -0
  92. data/test/unit/save_action_tests.rb +83 -0
  93. data/test/unit/save_service_tests.rb +264 -0
  94. data/test/unit/service_tests.rb +33 -0
  95. data/test/unit/service_validation_errors_tests.rb +107 -0
  96. data/test/unit/time_tests.rb +58 -0
  97. data/test/unit/view_models/breadcrumb_tests.rb +53 -0
  98. data/test/unit/wrap_and_call_method_tests.rb +163 -0
  99. data/test/unit/wrap_method_tests.rb +112 -0
  100. metadata +356 -7
  101. 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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MuchRails
2
- VERSION = "0.0.1"
4
+ VERSION = "0.2.0"
3
5
  end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "much-rails/view_models/breadcrumb"
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MuchRails; end
4
+
5
+ module MuchRails::ViewModels; end
6
+ MuchRails::ViewModels::Breadcrumb =
7
+ Struct.new(:name, :url) do
8
+ def render_as_link?
9
+ url.present?
10
+ end
11
+ end
@@ -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
@@ -1,5 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
- lib = File.expand_path("../lib", __FILE__)
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 = `git ls-files | grep "^[^.]"`.split($/)
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("assert", ["~> 2.18.4"])
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
- # TODO: gem.add_dependency("gem-name", ["~> 0.0.0"])
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
@@ -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("../..", __FILE__))
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
- # TODO: put test helpers here...
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!
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "much-rails/action"
4
+
5
+ module Actions; end
6
+
7
+ module Actions::Show
8
+ include MuchRails::Action
9
+
10
+ params_root :nested
11
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ url :root, "/"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "assert/factory"
2
4
 
3
5
  module Factory
@@ -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