Skip to content

Commit

Permalink
Fix and write specs, fix bugs, change minimal ruby version
Browse files Browse the repository at this point in the history
  • Loading branch information
AnotherRegularDude committed Dec 14, 2024
1 parent 3a674f9 commit c179520
Show file tree
Hide file tree
Showing 18 changed files with 425 additions and 72 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: "3.1"
ruby-version: "3.3"
bundler-cache: true
- name: Run Linter
run: bundle exec ci-helper RubocopLint
Expand All @@ -43,7 +43,7 @@ jobs:
strategy:
fail-fast: false
matrix:
ruby: ["2.7", "3.0"]
ruby: ["3.1", "3.2"]
experimental: [false]
include:
- ruby: head
Expand Down
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ inherit_gem:

AllCops:
DisplayCopNames: true
TargetRubyVersion: 3.2
TargetRubyVersion: 3.1

Naming/MethodParameterName:
AllowedNames: ["x", "y", "z"]
Expand Down
5 changes: 3 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ gemspec

gem "bundler-audit"
gem "ci-helper"
gem "dry-initializer"
gem "pry"
gem "qonfig"
gem "rake"
gem "rspec"
gem "rubocop-config-umbrellio"
gem "simplecov"
gem "simplecov-lcov"

gem "dry-initializer"
gem "smart_initializer"
gem "qonfig", "0.28.0"
8 changes: 2 additions & 6 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ PATH
remote: .
specs:
resol (1.0.0)
dry-initializer (~> 3.1)
smart_initializer (~> 0.7)

GEM
remote: https://rubygems.org/
specs:
activesupport (8.0.1)
activesupport (7.2.2.1)
base64
benchmark (>= 0.3)
bigdecimal
Expand All @@ -20,7 +18,6 @@ GEM
minitest (>= 5.1)
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
uri (>= 0.13.1)
ast (2.4.2)
base64 (0.2.0)
benchmark (0.4.0)
Expand Down Expand Up @@ -134,7 +131,6 @@ GEM
umbrellio-sequel-plugins (0.17.0)
sequel
unicode-display_width (2.6.0)
uri (1.0.2)

PLATFORMS
arm64-darwin-21
Expand All @@ -149,7 +145,7 @@ DEPENDENCIES
ci-helper
dry-initializer
pry
qonfig (= 0.28.0)
qonfig
rake
resol!
rspec
Expand Down
16 changes: 13 additions & 3 deletions lib/resol/initializers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ def apply!(service_class, initializer_name)
else
raise ArgumentError, "unknown initializer #{initializer_name}"
end

self.applied_classes << service_class.name
end

private
Expand All @@ -28,16 +30,24 @@ def apply!(service_class, initializer_name)

def validate_state!(service_class)
applied_parent = service_class
return if service_class.ancestors.none? { |klass| klass.name.start_with?(MOD_MATCH_REGEX) }
return if service_class.ancestors.none? { |klass| klass.inspect.start_with?(MOD_MATCH_REGEX) }

loop do
applied_parent = applied_parent.superclass or break

break if applied_classes.include?(applied_parent.name)
end

err_message = "#{applied_parent.name} or his superclasses manually include initializer dsl"
raise ArgumentError, err_message
if applied_parent.nil?
error!("use ::use_initializer! method on desired service class")
end

err_message = "#{applied_parent.name} or his superclasses already used initialize lib"
error!(err_message)
end

def error!(message)
raise ArgumentError, message
end
end
end
18 changes: 10 additions & 8 deletions lib/resol/plugins.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ module Resol
module Plugins
PLUGINS_PATH = Pathname("resol/plugins")
class Manager
def initialize
def initialize(target_class = nil)
self.plugins = []
self.target_class = target_class || Resol::Service
end

def plugin(plugin_name)
plugin_name = plugin_name.to_s
return if plugins.include?(plugin_name)

plugin_module = find_plugin_module(plugin_name)
Expand All @@ -27,21 +29,21 @@ def plugin(plugin_name)

private

attr_accessor :plugins
attr_accessor :plugins, :target_class

def find_plugin_module(plugin_name)
require PLUGINS_PATH.join(plugin_name)
Plugins.const_get(classify_plugin_name(plugin_name))
resolve_module(classify_plugin_name(plugin_name))
rescue LoadError, NameError => e
raise "Failed to load plugin '#{plugin_name}': #{e.message}"
raise ArgumentError, "Failed to load plugin '#{plugin_name}': #{e.message}"
end

def classify_plugin_name(string)
string.split(/_|-/).map!(&:capitalize).join
def resolve_module(module_name)
Plugins.const_get(module_name)
end

def target_class
Resol::Service
def classify_plugin_name(string)
string.split(/_|-/).map!(&:capitalize).join
end
end
end
Expand Down
7 changes: 7 additions & 0 deletions lib/resol/plugins/dummy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

module Resol
module Plugins
module Dummy; end
end
end
4 changes: 3 additions & 1 deletion lib/resol/plugins/return_in_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ def handle_catch(_service)
end

def call_service(service)
service.call.tap { |res| return unless res.is_a?(Service::Result) }
service.call.tap do |res|
return Resol::Service::NOT_EXITED unless res.is_a?(Service::Result)
end
end
end

Expand Down
2 changes: 2 additions & 0 deletions lib/resol/result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
module Resol
class UnwrapError < StandardError; end

# rubocop:disable Lint/EmptyClass
class Result; end
# rubocop:enable Lint/EmptyClass

class Success < Result
def initialize(value)
Expand Down
27 changes: 11 additions & 16 deletions lib/resol/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,17 @@ def message
end
end

module ChildMethodRestriction
def plugin(*)
raise NoMethodError
end

def manager
raise NoMethodError
end
end

include Resol::Builder
include Resol::Callbacks

Result = Struct.new(:data)
NOT_EXITED = Object.new.freeze
BASE_CLASS = self

Result = Struct.new(:data)

class << self
def inherited(klass)
klass.const_set(:Failure, Class.new(klass::Failure))
klass.extend(ChildMethodRestriction)
super
end

Expand All @@ -55,11 +46,15 @@ def use_initializer!(initializer_lib)
end

def plugin(...)
if self::BASE_CLASS != self
raise ArgumentError, "can load plugins only on base Resol::Service"
end

manager.plugin(...)
end

def call(*, **)
service = build(*, **)
def call(...)
service = build(...)

result = handle_catch(service) do
service.instance_variable_set(:@__performing__, true)
Expand Down Expand Up @@ -130,8 +125,8 @@ def check_performing
end
end

def proceed_return(data)
throw(self, data)
def proceed_return(service, data)
throw(service, data)
end
end
end
5 changes: 1 addition & 4 deletions resol.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/umbrellio/resol"
spec.license = "MIT"

spec.required_ruby_version = Gem::Requirement.new(">= 3.2.0")
spec.required_ruby_version = Gem::Requirement.new(">= 3.1.0")
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.include?("spec") }
spec.require_paths = ["lib"]

spec.add_dependency "dry-initializer", "~> 3.1"
spec.add_dependency "smart_initializer", "~> 0.7"
end
23 changes: 23 additions & 0 deletions spec/configuration_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
# frozen_string_literal: true

RSpec.describe Resol::Configuration do
before { allow(described_class).to receive(:smart_not_loaded?).and_return(const_not_loaded?) }

let(:const_not_loaded?) { true }

it "#smart_config returns nil" do
expect(described_class.smart_config).to eq(nil)
end

context "with loaded const" do
let(:const_not_loaded?) { false }

it "returns config" do
expect(described_class.smart_config).to eq(SmartCore::Initializer::Configuration.config)
end
end

context "with original method" do
before { allow(described_class).to receive(:smart_not_loaded?).and_call_original }

it "returns smartcore config" do
expect(described_class.smart_config).to eq(SmartCore::Initializer::Configuration.config)
end
end
end
79 changes: 79 additions & 0 deletions spec/initializers_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,83 @@
# frozen_string_literal: true

RSpec.describe Resol::Initializers do
def apply_initializer(forced_service_class = nil)
described_class.apply!(forced_service_class || service_class, initializer_name)
end

before { stub_const("InitializerTestClass", service_class) }

let(:service_class) do
Class.new(Resol::Service) do
def call
success!
end
end
end

let(:initializer_name) { :dry }
let(:dry_modules) do
["Dry::Initializer::Mixin::Root", start_with("Dry::Initializer::Mixin::Local")]
end

it "properly extend service class with initializer" do
apply_initializer
expect(service_class.ancestors.map(&:to_s)).to include(*dry_modules)
end

context "with unknown initializer lib" do
let(:initializer_name) { :kek }

specify do
expect { apply_initializer }.to raise_error(ArgumentError, "unknown initializer kek")
end
end

context "with already prepared parent" do
before { stub_const("SecondChildService", second_child_service) }

let(:service_class) do
Class.new(ReturnEngineService) do
def call
success!
end
end
end

let(:second_child_service) do
Class.new(InitializerTestClass)
end

let(:error_message) do
"ReturnEngineService or his superclasses already used initialize lib"
end

specify do
expect { apply_initializer(SecondChildService) }.to raise_error(ArgumentError, error_message)
end
end

context "with manually extended service" do
before { stub_const("SecondChildService", second_child_service) }

let(:service_class) do
Class.new(Resol::Service) do
extend Dry::Initializer

def call
success!
end
end
end

let(:second_child_service) do
Class.new(InitializerTestClass)
end

let(:error_message) { "use ::use_initializer! method on desired service class" }

specify do
expect { apply_initializer(SecondChildService) }.to raise_error(ArgumentError, error_message)
end
end
end
Loading

0 comments on commit c179520

Please sign in to comment.