initial commit, yay super-easy form objects
This commit is contained in:
commit
d910e0e837
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
*.gem
|
||||
*.rbc
|
||||
.bundle
|
||||
.config
|
||||
.yardoc
|
||||
Gemfile.lock
|
||||
InstalledFiles
|
||||
_yardoc
|
||||
coverage
|
||||
doc/
|
||||
lib/bundler/man
|
||||
pkg
|
||||
rdoc
|
||||
spec/reports
|
||||
test/tmp
|
||||
test/version_tmp
|
||||
tmp
|
4
Gemfile
Normal file
4
Gemfile
Normal file
@ -0,0 +1,4 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
# Specify your gem's dependencies in carapace.gemspec
|
||||
gemspec
|
22
LICENSE.txt
Normal file
22
LICENSE.txt
Normal file
@ -0,0 +1,22 @@
|
||||
Copyright (c) 2013 John Bintz
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
51
README.md
Normal file
51
README.md
Normal file
@ -0,0 +1,51 @@
|
||||
# CANDY WRAPPER
|
||||
|
||||
Use form objects with ease. Plugs into `inherited_resources` easily:
|
||||
|
||||
``` ruby
|
||||
# app/models/database_object.rb
|
||||
class DatabaseObject < Persistence::Base
|
||||
# ... persistence and relationships only ...
|
||||
end
|
||||
```
|
||||
|
||||
``` ruby
|
||||
# app/controllers/database_objects_controller.rb
|
||||
|
||||
class DatabaseObjectsController < ApplicationController
|
||||
inherit_resources
|
||||
|
||||
# for the parts of inherited_resources that actually persist models,
|
||||
# ensure that persistence takes placed within a CandyWrapper::ModelWrapper
|
||||
# form object. Those respond to save, assign_attributes, and update_attributes.
|
||||
wrap_in_form_object!
|
||||
end
|
||||
```
|
||||
|
||||
``` ruby
|
||||
# app/form_objects/database_object_form_object.rb
|
||||
|
||||
class DatabaseObjectFormObject < CandyWrapper::ModelWrapper
|
||||
def complex_parameter=(database_object, parameter_value)
|
||||
# do complex formatting here, probably for nested objects
|
||||
# database_object will be saved by this point
|
||||
end
|
||||
|
||||
# perform these actions before database_object is saved
|
||||
before_wrapped_save :process_first_parameter
|
||||
|
||||
def process_first_parameter=(database_object, parameter_value)
|
||||
# use normal accessors to set properties on database_object, it will be
|
||||
# saved when all before_wrapped_saved methods are run
|
||||
end
|
||||
|
||||
# there is no guarantee in the order that these will run, don't make them
|
||||
# depend on each other!
|
||||
end
|
||||
```
|
||||
|
||||
## Coming soon!
|
||||
|
||||
* Form objects that hang off of models as if they were relationships
|
||||
* A better readme!
|
||||
|
26
candy_wrapper.gemspec
Normal file
26
candy_wrapper.gemspec
Normal file
@ -0,0 +1,26 @@
|
||||
# coding: utf-8
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'candy_wrapper/version'
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "candy_wrapper"
|
||||
spec.version = CandyWrapper::VERSION
|
||||
spec.authors = ["John Bintz"]
|
||||
spec.email = ["john@coswellproductions.com"]
|
||||
spec.description = %q{Use form objects with ease.}
|
||||
spec.summary = %q{Use form objects with ease.}
|
||||
spec.homepage = ""
|
||||
spec.license = "MIT"
|
||||
|
||||
spec.files = `git ls-files`.split($/)
|
||||
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
||||
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_development_dependency "bundler", "~> 1.3"
|
||||
spec.add_development_dependency "rake"
|
||||
spec.add_development_dependency "rspec"
|
||||
spec.add_dependency 'activesupport'
|
||||
end
|
||||
|
4
lib/candy_wrapper.rb
Normal file
4
lib/candy_wrapper.rb
Normal file
@ -0,0 +1,4 @@
|
||||
require "candy_wrapper/version"
|
||||
require "candy_wrapper/model_wrapper"
|
||||
require "candy_wrapper/inherited_resources"
|
||||
|
59
lib/candy_wrapper/inherited_resources.rb
Normal file
59
lib/candy_wrapper/inherited_resources.rb
Normal file
@ -0,0 +1,59 @@
|
||||
require 'active_support/concern'
|
||||
|
||||
module CandyWrapper
|
||||
module InheritedResources
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
def __candy_wrapper__
|
||||
@__candy_wrapper__
|
||||
end
|
||||
|
||||
def wrap_in_form_object(options = {})
|
||||
@__candy_wrapper__ = {
|
||||
with: resource_class.name + "FormObject",
|
||||
only: [ :create, :update ]
|
||||
}.merge(options)
|
||||
end
|
||||
|
||||
def wrap_in_form_object!(*args)
|
||||
wrap_in_form_object(*args)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def build_resource
|
||||
get_resource_ivar || set_resource_ivar(
|
||||
if self.class.__candy_wrapper__[:only].include?(action_name.to_sym)
|
||||
object = end_of_association_chain.send(method_for_build)
|
||||
else
|
||||
super
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
def create_resource(object)
|
||||
if self.class.__candy_wrapper__[:only].include?(action_name.to_sym)
|
||||
wrapped_object = candy_wrapper_class.new(object, *resource_params)
|
||||
|
||||
wrapped_object.save
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def update_resource(object, attributes)
|
||||
if self.class.__candy_wrapper__[:only].include?(action_name.to_sym)
|
||||
wrapped_object = candy_wrapper_class.new(object)
|
||||
wrapped_object.update_attributes(*attributes)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def candy_wrapper_class
|
||||
@__candy_wrapper_class__ ||= self.class.__candy_wrapper__[:with].constantize
|
||||
end
|
||||
end
|
||||
end
|
||||
|
94
lib/candy_wrapper/model_wrapper.rb
Normal file
94
lib/candy_wrapper/model_wrapper.rb
Normal file
@ -0,0 +1,94 @@
|
||||
require 'delegate'
|
||||
|
||||
module CandyWrapper
|
||||
class ModelWrapper < SimpleDelegator
|
||||
def self.inherited(klass)
|
||||
klass.send(:extend, ClassMethods)
|
||||
|
||||
if klass.name && original = klass.name[/^(.*)FormObject$/, 1]
|
||||
klass.wraps original.constantize
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def wraps(klass = nil)
|
||||
if klass
|
||||
@__wraps__ = klass
|
||||
else
|
||||
@__wraps__
|
||||
end
|
||||
end
|
||||
|
||||
def before_wrapped_save(*args)
|
||||
@__before_wrapped_save__ ||= []
|
||||
|
||||
if args.empty?
|
||||
@__before_wrapped_save__
|
||||
else
|
||||
@__before_wrapped_save__ += args
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def __wraps__
|
||||
self.class.wraps
|
||||
end
|
||||
|
||||
def initialize(object, params = {})
|
||||
@__object__ = object
|
||||
|
||||
assign_attributes(params)
|
||||
end
|
||||
|
||||
def __getobj__
|
||||
@__object__
|
||||
end
|
||||
|
||||
def assign_attributes(attributes)
|
||||
@__params__ = attributes.dup
|
||||
end
|
||||
|
||||
def update_attributes(attributes)
|
||||
assign_attributes(attributes)
|
||||
|
||||
save
|
||||
end
|
||||
|
||||
def save
|
||||
self.class.before_wrapped_save.each do |before|
|
||||
send("#{before}=", @__object__, @__params__[before])
|
||||
end
|
||||
|
||||
@__object__.assign_attributes(__object_params__)
|
||||
|
||||
if result = @__object__.save
|
||||
setters_and_setter_params.each do |setter, setter_param|
|
||||
send(setter, @__object__, @__params__[setter_param])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def __object_params__
|
||||
object_params = @__params__.dup
|
||||
setter_params.each { |key| object_params.delete(key) }
|
||||
object_params
|
||||
end
|
||||
|
||||
def setter_params
|
||||
@__setter_params__ ||= setters.collect { |param| param.gsub('=', '').to_sym }
|
||||
end
|
||||
|
||||
def setters
|
||||
@__setters__ ||= (my_instance_methods.collect(&:to_s).find_all { |param| param[/=\Z/] } - self.class.before_wrapped_save)
|
||||
end
|
||||
|
||||
def setters_and_setter_params
|
||||
setters.zip(setter_params)
|
||||
end
|
||||
|
||||
def my_instance_methods
|
||||
@my_instance_methods ||= (self.class.instance_methods - ModelWrapper.instance_methods)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
3
lib/candy_wrapper/version.rb
Normal file
3
lib/candy_wrapper/version.rb
Normal file
@ -0,0 +1,3 @@
|
||||
module CandyWrapper
|
||||
VERSION = "0.0.1"
|
||||
end
|
51
spec/candy_wrapper/model_wrapper_spec.rb
Normal file
51
spec/candy_wrapper/model_wrapper_spec.rb
Normal file
@ -0,0 +1,51 @@
|
||||
require 'spec_helper'
|
||||
require 'candy_wrapper/model_wrapper'
|
||||
|
||||
describe CandyWrapper::ModelWrapper do
|
||||
describe '#update_attributes' do
|
||||
let(:model_class) {
|
||||
Class.new do
|
||||
attr_reader :saved, :attributes
|
||||
|
||||
def save
|
||||
@saved = true
|
||||
end
|
||||
|
||||
def assign_attributes(attributes)
|
||||
@attributes = attributes
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
let(:wrap_class) {
|
||||
klass = Class.new(CandyWrapper::ModelWrapper) do
|
||||
attr_reader :resource, :value
|
||||
|
||||
def setter=(resource, value)
|
||||
@resource, @value = resource, value
|
||||
end
|
||||
end
|
||||
|
||||
klass.send(:wraps, model_class)
|
||||
klass
|
||||
}
|
||||
|
||||
let(:setter_value) { 'setter value' }
|
||||
let(:base_attributes) { { :base => 'base' } }
|
||||
let(:attributes) { { :setter => setter_value }.merge(base_attributes) }
|
||||
|
||||
it 'should save the model and trigger the setters on the wrapper' do
|
||||
model = model_class.new
|
||||
wrap = wrap_class.new(model)
|
||||
|
||||
wrap.update_attributes(attributes)
|
||||
|
||||
model.saved.should be_true
|
||||
model.attributes.should be == base_attributes
|
||||
|
||||
wrap.resource.should == model
|
||||
wrap.value.should == setter_value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
4
spec/spec_helper.rb
Normal file
4
spec/spec_helper.rb
Normal file
@ -0,0 +1,4 @@
|
||||
require 'rspec'
|
||||
|
||||
$: << File.expand_path('../../lib')
|
||||
|
Loading…
Reference in New Issue
Block a user