frigate 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +7 -0
  5. data/Gemfile +10 -0
  6. data/Guardfile +67 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +31 -0
  9. data/Rakefile +13 -0
  10. data/frigate.gemspec +31 -0
  11. data/lib/frigate/form/association.rb +94 -0
  12. data/lib/frigate/form/base.rb +141 -0
  13. data/lib/frigate/form/property.rb +40 -0
  14. data/lib/frigate/form/synchronizer/base.rb +22 -0
  15. data/lib/frigate/form/synchronizer/basic.rb +75 -0
  16. data/lib/frigate/form/synchronizer/contract.rb +46 -0
  17. data/lib/frigate/form/synchronizer/form.rb +40 -0
  18. data/lib/frigate/form/synchronizer/fundamental.rb +17 -0
  19. data/lib/frigate/form/synchronizer.rb +14 -0
  20. data/lib/frigate/form.rb +16 -0
  21. data/lib/frigate/function.rb +41 -0
  22. data/lib/frigate/operation/action/base.rb +65 -0
  23. data/lib/frigate/operation/action/create.rb +21 -0
  24. data/lib/frigate/operation/action/update.rb +24 -0
  25. data/lib/frigate/operation/action.rb +12 -0
  26. data/lib/frigate/operation/base.rb +79 -0
  27. data/lib/frigate/operation/controller.rb +42 -0
  28. data/lib/frigate/operation/invalid_params_error.rb +7 -0
  29. data/lib/frigate/operation/renderable.rb +52 -0
  30. data/lib/frigate/operation/worker.rb +50 -0
  31. data/lib/frigate/operation.rb +16 -0
  32. data/lib/frigate/version.rb +3 -0
  33. data/lib/frigate.rb +61 -0
  34. data/spec/fixtures/user_form.rb +34 -0
  35. data/spec/frigate/form/base_spec.rb +120 -0
  36. data/spec/frigate/operation/base_spec.rb +52 -0
  37. data/spec/rails_test_app/Rakefile +6 -0
  38. data/spec/rails_test_app/app/controllers/application_controller.rb +5 -0
  39. data/spec/rails_test_app/app/helpers/application_helper.rb +2 -0
  40. data/spec/rails_test_app/app/models/user/profile/passport.rb +5 -0
  41. data/spec/rails_test_app/app/models/user/profile.rb +6 -0
  42. data/spec/rails_test_app/app/models/user.rb +5 -0
  43. data/spec/rails_test_app/bin/bundle +3 -0
  44. data/spec/rails_test_app/bin/rails +4 -0
  45. data/spec/rails_test_app/bin/rake +4 -0
  46. data/spec/rails_test_app/config/application.rb +30 -0
  47. data/spec/rails_test_app/config/boot.rb +4 -0
  48. data/spec/rails_test_app/config/database.yml +25 -0
  49. data/spec/rails_test_app/config/environment.rb +5 -0
  50. data/spec/rails_test_app/config/environments/development.rb +28 -0
  51. data/spec/rails_test_app/config/environments/production.rb +67 -0
  52. data/spec/rails_test_app/config/environments/test.rb +39 -0
  53. data/spec/rails_test_app/config/initializers/backtrace_silencers.rb +7 -0
  54. data/spec/rails_test_app/config/initializers/cookies_serializer.rb +3 -0
  55. data/spec/rails_test_app/config/initializers/filter_parameter_logging.rb +4 -0
  56. data/spec/rails_test_app/config/initializers/inflections.rb +16 -0
  57. data/spec/rails_test_app/config/initializers/mime_types.rb +4 -0
  58. data/spec/rails_test_app/config/initializers/session_store.rb +3 -0
  59. data/spec/rails_test_app/config/initializers/wrap_parameters.rb +14 -0
  60. data/spec/rails_test_app/config/locales/en.yml +23 -0
  61. data/spec/rails_test_app/config/routes.rb +56 -0
  62. data/spec/rails_test_app/config/secrets.yml +22 -0
  63. data/spec/rails_test_app/config.ru +4 -0
  64. data/spec/rails_test_app/db/migrate/20141212054646_create_users.rb +10 -0
  65. data/spec/rails_test_app/db/migrate/20141212054746_create_user_profiles.rb +10 -0
  66. data/spec/rails_test_app/db/migrate/20141212054847_create_user_profile_passports.rb +15 -0
  67. data/spec/rails_test_app/db/seeds.rb +7 -0
  68. data/spec/spec_helper.rb +84 -0
  69. metadata +217 -0
@@ -0,0 +1,17 @@
1
+ module Frigate
2
+ module Form
3
+ # Serves for synchronization form properties with model attributes/properties
4
+ module Synchronizer
5
+ # An abstract syncronizator, needs to be as superclass
6
+ class Fundamental
7
+ attr_reader :form
8
+
9
+ # initializes class, rly?????
10
+ # @param [Frigate::Form] form
11
+ def initialize(form)
12
+ @form = form
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ module Frigate
2
+ module Form
3
+ # Serves for synchronization form properties with model attributes/properties
4
+ module Synchronizer
5
+ # code; mb some configs
6
+ end
7
+ end
8
+ end
9
+ #
10
+ require 'frigate/form/synchronizer/fundamental'
11
+ require 'frigate/form/synchronizer/base'
12
+ require 'frigate/form/synchronizer/basic'
13
+ require 'frigate/form/synchronizer/form'
14
+ require 'frigate/form/synchronizer/contract'
@@ -0,0 +1,16 @@
1
+ #
2
+ # Is used for model validation outside of model
3
+ #
4
+ # @author Vladislav Pauk <vladislavpauk@gmail.com>
5
+ #
6
+ require 'active_support/core_ext/module/delegation'
7
+ #
8
+ module Frigate
9
+ # It's a form.
10
+ # @see Frigate::Form::Base
11
+ module Form
12
+ # code, mb some configuration
13
+ end
14
+ end
15
+ #
16
+ require 'frigate/form/base'
@@ -0,0 +1,41 @@
1
+ # @example
2
+ # class Song::AddArtistService < Frigate::Service
3
+ # property :song
4
+ # property :artist
5
+ #
6
+ # def function
7
+ # song.artists << artist
8
+ # end
9
+ # end
10
+ #
11
+ # Song::AddArtistService[song: song, artist: artist]
12
+ class Frigate::Function
13
+ class << self
14
+ # @param [Symbol] name
15
+ def property(name)
16
+ class_eval { attr_reader name }
17
+ end
18
+
19
+ # @param [Hash] attrs
20
+ def run(attrs)
21
+ new(attrs).run
22
+ end
23
+
24
+ alias_method :[], :run
25
+ end
26
+
27
+ # @param [Hash] attrs
28
+ def initialize(attrs)
29
+ attrs.each { |key, val| instance_variable_set("@#{key}", val) }
30
+ end
31
+
32
+ # to perform/run the service actions\tasks
33
+ def run
34
+ function
35
+ end
36
+
37
+ # here you should write your function code =)
38
+ def function
39
+ raise NotImplemented
40
+ end
41
+ end
@@ -0,0 +1,65 @@
1
+ module Frigate
2
+ module Operation
3
+ module Action
4
+ # Base class is an abstact class
5
+ # @abstract
6
+ class Base
7
+ class << self
8
+ # Initializes action class and pass args to instance run method
9
+ # @param [Frigate::Operation] operation receives an instace of subclass of Frigate::Operation
10
+ # @param [Hash] params
11
+ # @param [Hash] opts
12
+ def run(operation, params, opts={})
13
+ new(operation, opts).run(params)
14
+ end
15
+ end
16
+
17
+ attr_reader :opts, :operation, :model, :model_form, :action_result, :params
18
+
19
+ # @param [Frigate::Operation] operation
20
+ # @param [Hash] opts
21
+ def initialize(operation, opts={})
22
+ @operation = operation
23
+ @opts = opts
24
+ end
25
+
26
+ # Runs action's mechanism
27
+ def run(params)
28
+ (@params = params); action; model_form
29
+ end
30
+
31
+ # You should define an action in here
32
+ def action
33
+ raise NotImplementedError
34
+ end
35
+
36
+ protected
37
+
38
+ # Gets a model class of defined model class for operation
39
+ def model_klass
40
+ operation.class.model_klass
41
+ end
42
+
43
+ # Creates an instance of operation subclass of Frigate::Form for given model
44
+ def create_form(model)
45
+ operation.class.form_class.new(model)
46
+ end
47
+
48
+ # A getter/caller of operation_block from an operation class variable *operation_block*
49
+ # @note if no args passed then return the value of class variable *operation_block*
50
+ # @note if args passed then class variable *operation_block* is going to be called with these args
51
+ def operation_block(*args)
52
+ if args.empty?
53
+ operation.class.operation_block
54
+ else
55
+ if operation_block.nil?
56
+ raise StandardError.new('operation_block is nil')
57
+ else
58
+ operation.class.operation_block.call(*args)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,21 @@
1
+ module Frigate
2
+ module Operation
3
+ module Action
4
+ # Is here to perform create action of operation
5
+ class Create < Base
6
+ # An create action is defined in here
7
+ def action
8
+ @model = model_klass.new
9
+ @model_form = create_form(model)
10
+ if model_form.validate(params)
11
+ if operation_block
12
+ operation_block(model, params)
13
+ else
14
+ model_form.sync_with_model(save: true)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ module Frigate
2
+ module Operation
3
+ module Action
4
+ # Is here to perform update action of operation
5
+ class Update < Base
6
+ # An update action is defined in here
7
+ def action
8
+ @model = model_klass.find_by_id(params[:id]) # TODO: add id verification
9
+ @model_form = create_form(model)
10
+ if model_form.validate(params)
11
+ if operation_block
12
+ operation_block(model, params)
13
+ else
14
+ model_form.sync_with_model(save: true)
15
+ end
16
+ else
17
+ exception = InvalidParamsError.new('invalid params in %s' % operation.class.name)
18
+ raise (exception.tap { |e| e.errors = model_form.errors })
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ module Frigate
2
+ module Operation
3
+ # This module consists action classes for operation
4
+ module Action
5
+ # code; mb some configs
6
+ end
7
+ end
8
+ end
9
+ #
10
+ require 'frigate/operation/action/base'
11
+ require 'frigate/operation/action/create'
12
+ require 'frigate/operation/action/update'
@@ -0,0 +1,79 @@
1
+ module Frigate
2
+ module Operation
3
+ # Is here initialize the whole operation class
4
+ # A bigger description will be available soon
5
+ class Base
6
+ ALLOWED_ACTIONS = [:create, :update]
7
+
8
+ class << self
9
+ # Initializes form class and serves as a getter method
10
+ def form_class
11
+ @form_class ||= Class.new(Frigate::Form::Base)
12
+ end
13
+
14
+ # Serves as a getter method for *model_klass* class variable
15
+ def model_klass
16
+ @model_klass ? @model_klass : (raise StandardError.new('@model_klass nil'))
17
+ end
18
+
19
+ # Serves as a getter method for *operation_action* class variable
20
+ def operation_action
21
+ @operation_action ? @operation_action : (raise StandardError.new('@operation_action nil'))
22
+ end
23
+
24
+ # Serves as a getter method for *operation_block* class variable
25
+ def operation_block
26
+ # @operation_block.is_a?(Proc) ? @operation_block : (raise StandardError.new('operation block is not a Proc'))
27
+ @operation_block
28
+ end
29
+
30
+ # @param [Class] model_klass
31
+ def model(model_klass)
32
+ @model_klass = model_klass
33
+ end
34
+
35
+ # @param [Symbol] action
36
+ def action(action)
37
+ ALLOWED_ACTIONS.include?(action) ? (@operation_action = action.to_sym) : (raise ArgumentError.new('action is invalid'))
38
+ end
39
+
40
+ # @param [Proc] block
41
+ def operation(&block)
42
+ @operation_block = block
43
+ end
44
+
45
+ delegate :property, :has_one, to: :form_class
46
+
47
+ # @param [Hash] params
48
+ # @param [Hash] opts
49
+ def run(params, opts={})
50
+ new(opts).run(params)
51
+ end
52
+ end
53
+
54
+ attr_reader :params, :opts, :model_form
55
+
56
+ delegate :errors, :model, to: :model_form
57
+
58
+ # @param [Hash] opts
59
+ def initialize(opts={})
60
+ @opts = opts
61
+ end
62
+
63
+ # Runs the whole operation mechanism
64
+ # @param [Hash] params
65
+ # @return [Frigate::Operations] returns self
66
+ def run(params)
67
+ @params = Hashie::Mash.new(params)
68
+ # running actions
69
+ case self.class.operation_action
70
+ when :update
71
+ @model_form = Action::Update.run(self, params)
72
+ else
73
+ @model_form = Action::Create.run(self, params)
74
+ end
75
+ self # return self
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,42 @@
1
+ require 'active_support/concern'
2
+ module Frigate
3
+ module Operation
4
+ # Some stuff for controllers
5
+ module Controller
6
+ # Helpers for rails controllers
7
+ module Helpers
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ rescue_from InvalidParamsError, with: :invalid_params_error
12
+
13
+ def invalid_params_error(exception)
14
+ respond_to do |f|
15
+ f.json do
16
+ render status: 400, json: {
17
+ status: 'error',
18
+ data: exception.errors.messages
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ # run-operation helps to run operation elegantly
26
+ # @param [Frigate::Operation] klass
27
+ # @param [Hash] params
28
+ def run_operation(klass, params)
29
+ klass.run(params)
30
+ end
31
+
32
+ # render-operation helps to render operation data
33
+ # @param [Frigate::Operation] klass
34
+ # @param [Hash] params
35
+ def render_operation(*args)
36
+ run_operation(*args).render(self)
37
+ # raise run_operation(*args).errors.messages.inspect
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,7 @@
1
+ module Frigate
2
+ module Operation
3
+ class InvalidParamsError < StandardError
4
+ attr_accessor :errors
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,52 @@
1
+ module Frigate
2
+ module Operation
3
+ # allows operation to be rendered as json for now))
4
+ module Renderable
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ def render_block
11
+ @render_block
12
+ end
13
+
14
+ def render(render_block)
15
+ if render_block.is_a?(Proc)
16
+ @render_block ||= render_block
17
+ else
18
+ raise StandardError.new('render_block is not a Proc')
19
+ end
20
+ end
21
+ end
22
+
23
+ # @param [ActionController::Base] ctrl An Instance of subclass of ActionController::Base
24
+ def render(ctrl)
25
+ ctrl.respond_to do |f|
26
+ f.json do
27
+ ctrl.render status: (model_form.valid? ? 200 : 400), json: build_json(ctrl)
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ # @param [ActionController::Base] ctrl An Instance of subclass of ActionController::Base
35
+ def build_json(ctrl)
36
+ if model_form.valid?
37
+ Jbuilder.new { |_j| _j.status 'success'; _j.data { render_op(_j, self, ctrl) } }.target!
38
+ else
39
+ Jbuilder.new do |_j|
40
+ _j.status 'error'
41
+ _j.errors errors.messages
42
+ end.target!
43
+ end
44
+
45
+ end
46
+
47
+ def render_op(*args)
48
+ self.class.render_block.call(*args) if self.class.render_block.is_a?(Proc)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,50 @@
1
+ module Frigate
2
+ module Operation
3
+ # A module that allows operation to perform as a background job, using Sidekiq as BJ for now
4
+ module Worker
5
+ # Included hook
6
+ def self.included(base)
7
+ base.send(:include, Sidekiq::Worker) # TODO: this will work with any background gem.
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ # Class methods of class that includes *Worker* module
12
+ module ClassMethods
13
+ # Overrides standard *run* method in order to run an operation as a background job
14
+ # @param [Hash] params
15
+ # @param [Hash] options
16
+ def run(params, options = {})
17
+ serialized_params = serialize_params(params)
18
+ is_background? ? perform_async(serialized_params) : new.perform(serialized_params)
19
+ end
20
+
21
+ # Whether or not operation is background
22
+ # @return [Boolean] either background or not
23
+ def is_background?
24
+ !(Rails.env.test? || Rails.env.cucumber?) ||
25
+ (!ENV['FRIGATE_WORKER'].nil? || ENV['FRIGATE_WORKER'].downcase == 'true')
26
+ end
27
+
28
+ private
29
+ # serializes params
30
+ # @param [Hash] params
31
+ def serialize_params(params)
32
+ params # TODO: serialize AR for e.g.
33
+ end
34
+ end
35
+
36
+ # Method that runs operation mechanism. It's here because of Sidekiq::Worker needs it
37
+ # @param [Hash] params income parameters
38
+ def perform(params)
39
+ run(deserialize_params(params))
40
+ end
41
+
42
+ private
43
+ # deserializes params
44
+ # @param [Hash] params
45
+ def deserialize_params(params)
46
+ Hashie::Mash.new(params) # TODO: deserialize AR for e.g.
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,16 @@
1
+ require 'hashie/mash'
2
+ #
3
+ # This class serves as an abstact layer between model and controller
4
+ #
5
+ module Frigate
6
+ module Operation
7
+ # code; mb some configs
8
+ end
9
+ end
10
+ #
11
+ require 'frigate/operation/invalid_params_error'
12
+ require 'frigate/operation/worker'
13
+ require 'frigate/operation/controller'
14
+ require 'frigate/operation/renderable'
15
+ require 'frigate/operation/action'
16
+ require 'frigate/operation/base'
@@ -0,0 +1,3 @@
1
+ module Frigate
2
+ VERSION = "0.0.1" # the version of gem
3
+ end
data/lib/frigate.rb ADDED
@@ -0,0 +1,61 @@
1
+ require "frigate/version"
2
+ require 'active_support/core_ext/object/duplicable'
3
+ require 'active_support/core_ext/object/deep_dup'
4
+ require 'active_support/concern'
5
+ require 'active_model'
6
+ require 'hashie/mash'
7
+ #
8
+ # Description of this module is going to be relised soon
9
+ #
10
+ module Frigate
11
+ end
12
+ #
13
+ # Requiring Frigate's modules
14
+ #
15
+ require 'frigate/form'
16
+ require 'frigate/operation'
17
+ require 'frigate/function'
18
+ #
19
+ # Typecaster for boolean values. Source: http://drawingablank.me/blog/ruby-boolean-typecasting.html
20
+ #
21
+ class String
22
+ def to_bool
23
+ return true if self == true || self =~ (/^(true|t|yes|y|1)$/i)
24
+ return false if self == false || self.blank? || self =~ (/^(false|f|no|n|0)$/i)
25
+ raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
26
+ end
27
+ end
28
+ #
29
+ class Fixnum
30
+ def to_bool
31
+ return true if self == 1
32
+ return false if self == 0
33
+ raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
34
+ end
35
+ end
36
+ #
37
+ class TrueClass
38
+ def to_i;
39
+ 1;
40
+ end
41
+
42
+ def to_bool;
43
+ self;
44
+ end
45
+ end
46
+ #
47
+ class FalseClass
48
+ def to_i;
49
+ 0;
50
+ end
51
+
52
+ def to_bool;
53
+ self;
54
+ end
55
+ end
56
+ #
57
+ class NilClass
58
+ def to_bool;
59
+ false;
60
+ end
61
+ end
@@ -0,0 +1,34 @@
1
+ class UserForm < Frigate::Form::Base
2
+ property :email, validates: { presence: true }
3
+ has_one :user_profile do
4
+ property :first_name, validates: { presence: true }
5
+ property :last_name
6
+ property :skype
7
+ end
8
+ end
9
+
10
+ class UserFormCustom < Frigate::Form::Base
11
+ property :email, validates: { presence: true },
12
+ validate: [
13
+ Proc.new { error(:invalid) unless value =~ /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i },
14
+ ]
15
+ has_one :user_profile do
16
+ property :first_name, validates: { presence: true }
17
+ property :last_name
18
+ property :skype
19
+ end
20
+ end
21
+
22
+ class UserFormTree < Frigate::Form::Base
23
+ property :email
24
+ has_one :user_profile do
25
+ property :first_name
26
+ property :last_name
27
+ property :skype
28
+ has_one :user_profile_passport do
29
+ property :number
30
+ property :country
31
+ property :city
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,120 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Frigate::Form::Base do
4
+ let(:params) { { email: 'z1@zzz.zz', user_profile: { first_name: 'John', last_name: 'Doe', skype: 'johndoe' } } }
5
+ let(:tree_params) { params.tap { |_p| _p[:user_profile][:user_profile_passport] = { number: 'KL1234', country: 'Ukraine', city: 'Kiev' } } }
6
+ let(:user_model) { User.new.tap { |user| user.build_user_profile } }
7
+ let(:user_model_tree) { User.new.tap { |user| user.build_user_profile; user.profile.build_user_profile_passport } }
8
+
9
+ before(:example) do
10
+ @user_model = user_model
11
+ @user_model_tree = user_model_tree
12
+ @user_form = UserForm.new(@user_model)
13
+ @user_form_custom = UserFormCustom.new(@user_model)
14
+ @user_form_tree = UserFormTree.new(@user_model_tree)
15
+ end
16
+
17
+ context '#valid?' do
18
+ it 'returns true' do
19
+ @user_form.validate(params)
20
+ expect(@user_form.valid?).to be_truthy
21
+ end
22
+ it 'returns false' do
23
+ @user_form.validate({})
24
+ expect(@user_form.valid?).to be_falsey
25
+ end
26
+ end
27
+
28
+ context '#errors' do
29
+ it 'messages should not be empty' do
30
+ @user_form.validate({})
31
+ expect(@user_form.errors.messages).not_to be_empty
32
+ end
33
+ end
34
+
35
+ context '#sync_with_model' do
36
+ it 'should sync params with model' do
37
+ @user_form.validate(params)
38
+ @user_form.sync_with_model
39
+ expect(@user_model.email).to eq(params[:email])
40
+ expect(@user_model.user_profile.first_name).to eq(params[:user_profile][:first_name])
41
+ end
42
+ end
43
+
44
+ context 'contract' do
45
+ before(:example) do
46
+ @user_form = UserForm.new(@user_model, contract: true)
47
+ @user_form.validate
48
+ end
49
+
50
+ context '#valid?' do
51
+ it 'returns false' do
52
+ expect(@user_form.valid?).to be_falsey
53
+ end
54
+ end
55
+
56
+ context '#errors' do
57
+ it 'messages should not be empty' do
58
+ expect(@user_form.errors.messages).not_to be_empty
59
+ end
60
+ end
61
+ end
62
+
63
+ context 'custom validations' do
64
+ context '#valid?' do
65
+ it 'return true' do
66
+ @user_form_custom.validate(params)
67
+ expect(@user_form_custom.valid?).to be_truthy
68
+ end
69
+ it 'return false' do
70
+ params[:email] = 'bad-email.com'
71
+ @user_form_custom.validate(params)
72
+ expect(@user_form_custom.valid?).to be_falsey
73
+ end
74
+ end
75
+ end
76
+
77
+ context 'long tree' do
78
+ context '#sync_with_model' do
79
+ it 'should sync params with model' do
80
+ @user_form_tree.validate(tree_params)
81
+ @user_form_tree.sync_with_model
82
+ expect(@user_model_tree.profile.passport.number).to eq(params[:user_profile][:user_profile_passport][:number])
83
+ end
84
+ end
85
+ end
86
+
87
+ context 'delegation' do
88
+ before(:example) do
89
+ @user_form.validate(params)
90
+ end
91
+
92
+ it 'properties' do
93
+ expect(@user_form.email).to be_a(::Frigate::Form::Property)
94
+ end
95
+
96
+ it 'associations' do
97
+ expect(@user_form.user_profile).to be_a(::Frigate::Form::Association)
98
+ expect(@user_form.user_profile.first_name).to be_a(::Frigate::Form::Property)
99
+ end
100
+ end
101
+
102
+ describe Frigate::Form::Property do
103
+ context '#root' do
104
+ it 'should be instance of Frigate::Form::Base' do
105
+ @user_form.validate(params)
106
+ expect(@user_form.email.root).to be_a(Frigate::Form::Base)
107
+ expect(@user_form.user_profile.first_name.root).to be_a(Frigate::Form::Base)
108
+ end
109
+ end
110
+ end
111
+
112
+ describe Frigate::Form::Association do
113
+ context '#root' do
114
+ it 'should be instance of Frigate::Form::Base' do
115
+ @user_form.validate(params)
116
+ expect(@user_form.user_profile.root).to be_a(Frigate::Form::Base)
117
+ end
118
+ end
119
+ end
120
+ end