Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relax activesupport dependency #236

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/generators/light_service/generator_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ def must_gen_tests?
end

def create_required_gen_vals_from(name)
# Not using dry-inflector here, because generators are used only
# within Rails project thus we can relay on ActiveSupport presence.
# Maybe plan to split LightService::Generators into a separate
# gem (e.g.: light_service-rails-generators)
path_parts = name.underscore.split('/')

{
Expand Down
3 changes: 2 additions & 1 deletion lib/light-service.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'logger'
require 'active_support/core_ext/string'
require 'i18n'
require 'structured_warnings'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're requiring structured_warnings in light-service.rb we probably don't need to re-require them again in the rest of the files, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totaly agree: OR in the manifest OR in single files. In both places is just confusing and conceptually wrong.


require 'light-service/version'

Expand Down
4 changes: 2 additions & 2 deletions lib/light-service/action.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require 'active_support/deprecation'
require 'structured_warnings'

module LightService
module Action
Expand All @@ -9,7 +9,7 @@ def self.extended(base_class)
def self.included(base_class)
msg = "including LightService::Action is deprecated. " \
"Please use `extend LightService::Action` instead"
ActiveSupport::Deprecation.warn(msg)
warn(StructuredWarnings::DeprecatedMethodWarning, msg)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and wherever we thrown a warn, if this gem will remain in, I'd like to have a class LightService::Deprecation < StructuredWarnings::Base; end to use insted of directly expose the gem's built-in.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm completely for that course of action.

base_class.extend Macros
end

Expand Down
6 changes: 3 additions & 3 deletions lib/light-service/context.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require 'active_support/deprecation'
require 'structured_warnings'

module LightService
module Outcomes
Expand Down Expand Up @@ -61,7 +61,7 @@ def reset_skip_remaining!
def outcome
msg = '`Context#outcome` attribute reader is ' \
'DEPRECATED and will be removed'
ActiveSupport::Deprecation.warn(msg)
warn(StructuredWarnings::DeprecatedMethodWarning, msg)
@outcome
end

Expand Down Expand Up @@ -103,7 +103,7 @@ def fail_with_rollback!(message = nil, error_code = nil)
def skip_all!(message = nil)
warning_msg = "Using skip_all! has been deprecated, " \
"please use `skip_remaining!` instead."
ActiveSupport::Deprecation.warn(warning_msg)
warn(StructuredWarnings::DeprecatedMethodWarning, warning_msg)

skip_remaining!(message)
end
Expand Down
10 changes: 9 additions & 1 deletion lib/light-service/localization_adapter.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
require "dry/inflector"

module LightService
class LocalizationAdapter
attr_reader :inflector

def initialize
@inflector = Dry::Inflector.new
end

def failure(message_or_key, action_class, i18n_options = {})
find_translated_message(message_or_key,
action_class,
Expand Down Expand Up @@ -38,7 +46,7 @@ def translate(key, action_class, options = {})
end

def i18n_scope_from_class(action_class, type)
"#{action_class.name.underscore}.light_service.#{type.to_s.pluralize}"
"#{inflector.underscore(action_class.name)}.light_service.#{inflector.pluralize(type.to_s)}"
end
end
end
2 changes: 1 addition & 1 deletion lib/light-service/orchestrator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def scoped_reduction(ctx, steps)
def issue_deprecation_warning_for(method_name)
msg = "`Orchestrator##{method_name}` is DEPRECATED and will be " \
"removed, please switch to `Organizer##{method_name} instead. "
ActiveSupport::Deprecation.warn(msg)
warn(StructuredWarnings::DeprecatedMethodWarning, msg)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/light-service/organizer.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require 'active_support/deprecation'
require 'structured_warnings'

module LightService
module Organizer
Expand All @@ -10,7 +10,7 @@ def self.extended(base_class)
def self.included(base_class)
warning_msg = "including LightService::Organizer is deprecated. " \
"Please use `extend LightService::Organizer` instead"
ActiveSupport::Deprecation.warn(warning_msg)
warn(StructuredWarnings::DeprecatedMethodWarning, warning_msg)
extended(base_class)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/light-service/organizer/verify_call_method_exists.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def self.run(klass, first_caller = '')
"its entry method (the one that calls with & reduce) " \
"should be named `call`. " \
"Please use #{klass}.call going forward."
ActiveSupport::Deprecation.warn(warning_msg)
warn(StructuredWarnings::DeprecatedMethodWarning, warning_msg)
end

def self.caller_method(first_caller)
Expand Down
3 changes: 3 additions & 0 deletions light-service.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ Gem::Specification.new do |gem|
gem.required_ruby_version = '>= 2.6.0'

gem.add_runtime_dependency("activesupport", ">= 4.0.0")
gem.add_runtime_dependency("i18n")
gem.add_runtime_dependency("dry-inflector")
gem.add_runtime_dependency("structured_warnings")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I missed these additions. So instead of having just AS, we are adding 3 more dependencies.
I wish we could achieve the same functionality with no additional gems. But maybe I am just asking too much.

I wonder what ppl think about this change.

Copy link
Contributor Author

@alessandro-fazzi alessandro-fazzi Jun 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We’re adding only 2 more dependencies, since i18n is already in through AS at the moment.

I explicitly required it as a dep in order to have a functioning gemspec even considering AS removal and without leaving remainders for future work.

Speaking about the balance between AS and the two new gems: my sentiment is that with the two gems we bring less code than with AS alone. We should analyze it more scientifically tho.

For sure we have the achievement of not having a big rails ecosystem’s gem, leaving LS more desirable as cross-framework and franework-less solution.

Speaking of deprecation warnings: I previously tried to implement them using Gem::Deprecate, but it resulted to me as an inadequate tool out of its absolute standard concept. Hard to adapt. I think it would be feasible to write a dedicated Logger and implement some logic inside it in order to achieve a simple custom deprecation warner. This would be intended as a pragmatic and simpler alternative to structured_warning gem.
If you’d like to check a draft implementation I could try to write a separate draft PR in the second half of July.

About the inflector I’m really opinionated: I would not even try to reinvent the wheel on such a matter. Moreover I sincerely invite you to read dry-inflector’s source code: it’s astonishing small, tidy and simple; and it’s a completely standalone gem. Obviously we could copy that few methods we need, but pro and cons considered I think it’s a solid choice to bring it in.

Thanks for the feedback 😊


gem.add_development_dependency("generator_spec", "~> 0.9.4")
gem.add_development_dependency("test-unit", "~> 3.0") # Needed for generator specs.
Expand Down
21 changes: 11 additions & 10 deletions spec/acceptance/include_warning_spec.rb
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
require 'spec_helper'
require 'structured_warnings_helper'

describe "Including is discouraged" do
context "when including LightService::Organizer" do
it "gives warning" do
expected_msg = "including LightService::Organizer is deprecated. " \
"Please use `extend LightService::Organizer` instead"
expect(ActiveSupport::Deprecation).to receive(:warn)
.with(expected_msg)

class OrganizerIncludingLS
include LightService::Organizer
end
expect do
class OrganizerIncludingLS
include LightService::Organizer
end
end.to warn_with(StructuredWarnings::DeprecatedMethodWarning, expected_msg)
Comment on lines +10 to +14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests are great! We should remember to remove them when the actual removal takes place. 👍🏻

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given this discussion #236 (comment) it's still to take a decision about the use of that library.

That said and considering that whatever implementation will be it will have a test: remembering to remove deprecation from code will bring a red CI. That should be a good post-it to remove the test too ;)

end
end

context "when including LightService::Action" do
it "gives warning" do
expected_msg = "including LightService::Action is deprecated. " \
"Please use `extend LightService::Action` instead"
expect(ActiveSupport::Deprecation).to receive(:warn)
.with(expected_msg)

class ActionIncludingLS
include LightService::Action
end
expect do
class ActionIncludingLS
include LightService::Action
end
end.to warn_with(StructuredWarnings::DeprecatedMethodWarning, expected_msg)
end
end
end
17 changes: 7 additions & 10 deletions spec/acceptance/not_having_call_method_warning_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,22 @@
describe "Organizer should invoke with/reduce from a call method" do
context "when the organizer does not have a `call` method" do
it "gives warning" do
expect(ActiveSupport::Deprecation)
.to receive(:warn)
.with(/^The <OrganizerWithoutCallMethod> class is an organizer/)

class OrganizerWithoutCallMethod
extend LightService::Organizer

def self.do_something
reduce([])
end
end

OrganizerWithoutCallMethod.do_something
expect { OrganizerWithoutCallMethod.do_something }.to warn_with(
StructuredWarnings::DeprecatedMethodWarning,
/^The <OrganizerWithoutCallMethod> class is an organizer/
)
end
end

context "when the organizer has the `call` method" do
it "does not issue a warning" do
expect(ActiveSupport::Deprecation)
.not_to receive(:warn)

class OrganizerWithCallMethod
extend LightService::Organizer

Expand All @@ -33,7 +28,9 @@ def self.call
end
end

OrganizerWithCallMethod.call
expect { OrganizerWithCallMethod.call }.not_to warn_with(
StructuredWarnings::DeprecatedMethodWarning
)
end
end
end
5 changes: 2 additions & 3 deletions spec/acceptance/skip_all_warning_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ class SkipAllDeprecatedAction

expected_msg = "Using skip_all! has been deprecated, " \
"please use `skip_remaining!` instead."
expect(ActiveSupport::Deprecation).to receive(:warn)
.with(expected_msg)

SkipAllDeprecatedAction.execute
expect { SkipAllDeprecatedAction.execute }
.to warn_with(StructuredWarnings::DeprecatedMethodWarning, expected_msg)
end
end
11 changes: 9 additions & 2 deletions spec/context_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'spec_helper'
require 'structured_warnings_helper'
require 'test_doubles'

RSpec.describe LightService::Context do
Expand Down Expand Up @@ -152,9 +153,15 @@
end

it "warns about the outcome attribute reader being deprecated" do
expect(ActiveSupport::Deprecation).to receive(:warn)
expected_msg = '`Context#outcome` attribute reader is ' \
'DEPRECATED and will be removed'

expect(context.outcome).to eq(::LightService::Outcomes::SUCCESS)
expect { context.outcome }.to warn_with(StructuredWarnings::DeprecatedMethodWarning, expected_msg)

# Since the warning is already tested, do not pollute rspec output here
StructuredWarnings::DeprecatedMethodWarning.disable do
expect(context.outcome).to eq(::LightService::Outcomes::SUCCESS)
end
end

it "can contain false values" do
Expand Down
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@
require 'stringio'
require 'fileutils'
require 'generator_spec'
require 'structured_warnings_helper'

I18n.enforce_available_locales = true
60 changes: 60 additions & 0 deletions spec/structured_warnings_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require 'structured_warnings/test'

module StructuredWarningHelper
module_function

def parse_arguments(args) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
args = args.clone
first = args.shift

if first.is_a?(Class) && first <= StructuredWarnings::Base
warning = first
message = args.shift

elsif first.is_a?(Class) && !(first <= StructuredWarnings::Base)
raise ArgumentError, 'Warning issued with a class not inheriting from StructuredWarnings::Base'

elsif first.is_a? StructuredWarnings::Base
warning = first.class
message = first.message

elsif first.is_a? String
warning = StructuredWarnings::StandardWarning
message = first

else
warning = StructuredWarnings::Base
message = nil
end

unless args.empty?
raise ArgumentError,
"wrong number of arguments (#{args.size + 2} for 2)"
end

return warning, message
end

def args_inspect(args)
args.map(&:inspect).join(', ')
end
end

RSpec::Matchers.define :warn_with do |*args|
supports_block_expectations
warning, message = StructuredWarningHelper.parse_arguments(args)

match do |block|
w = StructuredWarnings::Test::Warner.new
StructuredWarnings.with_warner(w, &block)
expect(w.warned?(warning, message)).to be true
end

failure_message do |_block|
"<#{StructuredWarningHelper.args_inspect(args)}> has not been emitted."
end

failure_message_when_negated do |_block|
"<#{StructuredWarningHelper.args_inspect(args)}> has been emitted but it was not expected."
end
end
8 changes: 2 additions & 6 deletions spec/support.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
RSpec.shared_context 'expect orchestrator warning' do
before do
expect(ActiveSupport::Deprecation)
.to receive(:warn)
.with(/^`Orchestrator#/)
.at_least(:once)
around(:example) do |example|
expect { example.run }.to warn_with StructuredWarnings::DeprecatedMethodWarning
end
end