Wrapper Based DCI framework for OOP done right.
Add this line to your application's Gemfile:
gem'wrapper_based'And then execute:
$ bundle
Includes role components into classes. For each role it defines private accessor methods.
It accepts Classes that can be initialized with an argument, like so:
classSignsUser < Struct.new(:signed)defin!(user)signed[:user_id]=user.idenddefout!signed.delete(:user_id)@user=nilenddefout?signed[:user_id].nil? || in?enddefin?
!user.nil?enddefuser@user ||= by(id: signed[:user_id])enddefby(**identification)User.find_byidentificationenddefwith(**credentials)User.newcredentialsenddefup!(user)user.save && userifUser.validate_registering(user)endendAssign values using role binding methods prefixed by 'with_' and ended by an exclamation mark '!'.
classApplicationControllerincludeDCI::Roles(:current_user,logged: SignsUser)before_action->{with_logged!session}helper_method:current_user,:loggedprivatedefauthenticate_user!iflogged.out?flash[:error]="You must be logged in to access this section"redirect_tologin_urlelsewith_current_user!logged.userendendendclassLogoutController < ApplicationControllerincludeDCI::Roles(signing: SignsUser)before_action->{with_signing!session}defdestroysigning.out!redirect_toroot_urlendendIt also accept Modules but no procedural code allowed, meaning only call the role player object methods and avoid calling the other methods defined in the Module.
moduleUserParamsdefregistrationpermit(:username,:email)enddefloginpermit(:username,:email)enddefsecuritypermit(:password,:password_confirmation,:code)enddefpasswordfetch(:password,'')endendMass assign values to multiple components using 'with!' method.
classLoginController < ApplicationControllerincludeDCI::Roles(signing: SignsUser,user_params: UserParams,login: HasEncryptedPassword)before_action->{with!signing: session,user_params: params.require(:user)}before_action->{with!login: signing.by(user_params.login)}defnew;enddefcreateiflogin.authenticate(user_params.password)signing.in!loginredirect_tologin,notice: 'Welcome, you are now logged in.'elseflash[:danger]='Invalid credentials.'render:new,status: :unauthorizedendendendA role's instance variable holds plain value (without the new behavior).
classGiftToy < DCI::Context(:toy,gifter: Buyer,giftee: Recipient)defcall(toy=@toy)gift=gifter.buygiftee.receivegiftendendReturns call method as a Proc.
['Card Wars','Ice Ninja Manual','Bacon'].map &GiftToy[gifter: 'Jake',giftee: 'Finn']A shortcut for instantiating the context by passing the collaborators and then executing the context call method.
Funds::TransferMoney.(from: @account1,to: @account2,amount: 50)Which is equivalent to:
Funds::TransferMoney.new(from: @account1,to: @account2,amount: 50).callMoney Transfer | Djikstra | Toy Shop | Acapella | Background Job | Facade | HTTP API Client | all examples
After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/RichOrElse/wrapper-based.
The gem is available as open source under the terms of the MIT License.