diff --git a/CHANGELOG.md b/CHANGELOG.md index bdf35e5..8174d3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,24 @@ -# HEAD +# Pavlov Changelog -Lots and lots of backwards incompatible breakage. +## HEAD + +This release brings forth lots and lots of incompatibilities. Where possible, we've tried to keep a backwards-compatible API available. You can activate this by requiring `pavlov/alpha_compatibility'. + +#### New Stuff: + +* Pavlov now uses Virtus for what used to be called `arguments`. Instead of specifying a list of arguments, you can now specify attributes individually, with optional defaults. Check the README on all the cool stuff you can do with these Virtus-based attributes. + +#### Deprecations: + +If you want to retain deprecated functionality, you can `require 'pavlov/alpha_compatibility'`. + +* Deprecated `arguments` in operations. +* Deprecated `pavlov_options` that were used by the helpers. + +#### Completely removed: -* Now using Virtus for what used to be called `arguments`. Check the README on how to use the new `attribute`s. * Removed support for `finish_initialize`. Override the `initialize` method and call `super` instead. -# 0.1.0 +## 0.1.0 Initial alpha-release. Here be dragons. diff --git a/lib/pavlov.rb b/lib/pavlov.rb index 5d3c05b..cd2807f 100644 --- a/lib/pavlov.rb +++ b/lib/pavlov.rb @@ -38,3 +38,4 @@ def self.query command_name, *args require_relative 'pavlov/query' require_relative 'pavlov/interactor' require_relative 'pavlov/version' +require_relative 'pavlov/alpha_compatibility' diff --git a/lib/pavlov/alpha_compatibility.rb b/lib/pavlov/alpha_compatibility.rb new file mode 100644 index 0000000..484baeb --- /dev/null +++ b/lib/pavlov/alpha_compatibility.rb @@ -0,0 +1,74 @@ +require 'pavlov' + +module Pavlov + def self.old_command command_name, *args + class_name = "Commands::"+string_to_classname(command_name) + klass = get_class_by_string(class_name) + attributes = arguments_to_attributes(klass, args) + klass.new(attributes).call + end + + def self.old_interactor command_name, *args + class_name = "Interactors::"+string_to_classname(command_name) + klass = get_class_by_string class_name + attributes = arguments_to_attributes(klass, args) + klass.new(attributes).call + end + + def self.old_query command_name, *args + class_name = "Queries::"+string_to_classname(command_name) + klass = get_class_by_string class_name + attributes = arguments_to_attributes(klass, args) + klass.new(attributes).call + end + + def self.arguments_to_attributes(operation_class, arguments) + attribute_keys = operation_class.attribute_set.map(&:name) + + # TODO: this can be done so much better, but I don't know how. + hash={} + arguments.each_with_index do |value, index| + hash[attribute_keys[index].to_sym] = value + end + return hash + end + + module Helpers + def old_interactor name, *args + args = add_compatablity_pavlov_options args + Pavlov.old_interactor name, *args + end + + def old_query name, *args + args = add_compatablity_pavlov_options args + Pavlov.old_query name, *args + end + + def old_command name, *args + args = add_compatablity_pavlov_options args + Pavlov.old_command name, *args + end + + private + def add_compatablity_pavlov_options args + # TODO: we should do this at a point where we know how many arguments we need + # so we can decide if we need to merge with another options object or + # just add it. + if pavlov_options != {} + args << pavlov_options + end + args + end + end + + module Operation + module ClassMethods + def arguments(*args) + # Add generic attribute for each argument + args.each do |argument| + attribute argument, Object + end + end + end + end +end diff --git a/lib/pavlov/helpers.rb b/lib/pavlov/helpers.rb index f166707..7107d04 100644 --- a/lib/pavlov/helpers.rb +++ b/lib/pavlov/helpers.rb @@ -1,18 +1,18 @@ module Pavlov module Helpers - def interactor name, *args - args = add_pavlov_options args - Pavlov.interactor name, *args + def interactor name, hash + hash = add_pavlov_options hash + Pavlov.interactor name, hash end - def query name, *args - args = add_pavlov_options args - Pavlov.query name, *args + def query name, hash + hash = add_pavlov_options hash + Pavlov.query name, hash end - def command name, *args - args = add_pavlov_options args - Pavlov.command name, *args + def command name, hash + hash = add_pavlov_options hash + Pavlov.command name, hash end def pavlov_options @@ -20,14 +20,17 @@ def pavlov_options end private - def add_pavlov_options args - # TODO: we should do this at a point where we know how many arguments we need - # so we can decide if we need to merge with another options object or - # just add it. + def add_pavlov_options hash if pavlov_options != {} - args << pavlov_options + hash ||= {} + + if hash.has_key? 'pavlov_options' + hash[:pavlov_options] = pavlov_options.merge(hash[:pavlov_options]) + else + hash[:pavlov_options] = pavlov_options + end end - args + hash end end end diff --git a/lib/pavlov/operation.rb b/lib/pavlov/operation.rb index d70407c..25b4606 100644 --- a/lib/pavlov/operation.rb +++ b/lib/pavlov/operation.rb @@ -28,10 +28,6 @@ def call(*args, &block) private - def pavlov_options - @options - end - def raise_unauthorized(message='Unauthorized') raise Pavlov::AccessDenied, message end diff --git a/spec/integration/alpha_compatibility_spec.rb b/spec/integration/alpha_compatibility_spec.rb new file mode 100644 index 0000000..8698eae --- /dev/null +++ b/spec/integration/alpha_compatibility_spec.rb @@ -0,0 +1,67 @@ +require_relative '../spec_helper' +require 'pavlov' +require 'pavlov/alpha_compatibility' + +describe "Pavlov Alpha Compatibility" do + include Pavlov::Helpers + + describe 'retains .arguments' do + before do + stub_const "Interactors", Module.new + + class Interactors::OldStyleInteractor + include Pavlov::Interactor + arguments :title, :published + + def authorized? + true + end + + def execute + published ? title.upcase! : title + end + end + end + + it 'supports old-style arguments definition' do + expect(old_interactor(:old_style_interactor, 'foo', false)).to eq('foo') + expect(old_interactor(:old_style_interactor, 'foo', true)).to eq('FOO') + end + end + + describe 'retains pavlov_options' do + let(:current_user) { double("User", name: "John") } + def pavlov_options + {current_user: current_user} + end + + before do + stub_const "Queries", Module.new + stub_const "Interactors", Module.new + class Queries::FindUppercaseName + include Pavlov::Query + + attribute :pavlov_options, Hash, default: {} + + def execute + pavlov_options[:current_user].name.upcase + end + end + + class Interactors::ShoutyGreeting + include Pavlov::Interactor + + attribute :pavlov_options, Hash, default: {} + + def authorized?; true; end + def execute + "OHAI, #{old_query :find_uppercase_name}" + end + end + end + + it 'passes the pavlov_options from operation to operation' do + expect(old_interactor :shouty_greeting).to eq("OHAI, JOHN") + end + end +end diff --git a/spec/pavlov/helpers_spec.rb b/spec/pavlov/helpers_spec.rb index 41f2fba..d2e737e 100644 --- a/spec/pavlov/helpers_spec.rb +++ b/spec/pavlov/helpers_spec.rb @@ -8,12 +8,12 @@ include Pavlov::Helpers def test - interactor :interactor_name, 'argument1', 'argument2' + old_interactor :interactor_name, 'argument1', 'argument2' end end instance = dummy_class.new - Pavlov.should_receive(:interactor) + Pavlov.should_receive(:old_interactor) .with(:interactor_name, 'argument1', 'argument2') instance.test @@ -29,12 +29,12 @@ def pavlov_options end def test - interactor :interactor_name, 'argument1', 'argument2' + old_interactor :interactor_name, 'argument1', 'argument2' end end instance = dummy_class.new - - Pavlov.should_receive(:interactor) + + Pavlov.should_receive(:old_interactor) .with(:interactor_name, 'argument1', 'argument2', hash) instance.test