frigate 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c31f5d170fc9bb2a589fc06611dd6f216706562a
4
+ data.tar.gz: 2e1b8d78dbe0ef524c4a92390af756f23115f242
5
+ SHA512:
6
+ metadata.gz: 0eb87b749cda6c1f3cf39d60b6066be1e3eca7d81a1c262b0a3f6ad79cecbb8ccde1bd001def5288dde2c978cb5dfea080d8773996e85ecf1cf1b5caae075fea
7
+ data.tar.gz: b0ddf19c44b1794f463217bef7747655502b218f5217d44fe3e3a49b79e9f7199a38da64da291e48768bac2146279db29576b05ec9372b4f763ba20e95005e7c
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ .rvmrc
16
+ .ruby-version
17
+ .ruby-gemset
18
+ *.log
19
+ .keep
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.5
4
+ - 2.0.0
5
+ - 1.9.3
6
+ gemfile:
7
+ - Gemfile
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '~> 4.1'
4
+ gem 'sqlite3', '~> 1.3.10'
5
+ gem 'database_cleaner', '~> 1.3.0'
6
+ gem 'rspec', '~> 3.1.0'
7
+ gem 'guard-rspec', '~> 4.4.2'
8
+
9
+ # Specify your gem's dependencies in frigate.gemspec
10
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,67 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ # directories %(app lib config test spec feature)
6
+
7
+ ## Uncomment to clear the screen before every task
8
+ # clearing :on
9
+
10
+ # Note: The cmd option is now required due to the increasing number of ways
11
+ # rspec may be run, below are examples of the most common uses.
12
+ # * bundler: 'bundle exec rspec'
13
+ # * bundler binstubs: 'bin/rspec'
14
+ # * spring: 'bin/rspec' (This will use spring if running and you have
15
+ # installed the spring binstubs per the docs)
16
+ # * zeus: 'zeus rspec' (requires the server to be started separately)
17
+ # * 'just' rspec: 'rspec'
18
+
19
+ guard :rspec, cmd: "bundle exec rspec" do
20
+ require "ostruct"
21
+
22
+ # Generic Ruby apps
23
+ rspec = OpenStruct.new
24
+ rspec.spec = ->(m) { "spec/#{m}_spec.rb" }
25
+ rspec.spec_dir = "spec"
26
+ rspec.spec_helper = "spec/spec_helper.rb"
27
+
28
+ watch(%r{^spec/.+_spec\.rb$})
29
+ watch(%r{^lib/(.+)\.rb$}) { |m| rspec.spec.("lib/#{m[1]}") }
30
+ watch(rspec.spec_helper) { rspec.spec_dir }
31
+
32
+ # # Rails example
33
+ # rails = OpenStruct.new
34
+ # rails.app = %r{^app/(.+)\.rb$}
35
+ # rails.views_n_layouts = %r{^app/(.*)(\.erb|\.haml|\.slim)$}
36
+ # rails.controllers = %r{^app/controllers/(.+)_controller\.rb$}
37
+ # rails.routes = "config/routes.rb"
38
+ # rails.app_controller = "app/controllers/application_controller.rb"
39
+ # rails.spec_helper = "spec/rails_helper.rb"
40
+ # rails.spec_support = %r{^spec/support/(.+)\.rb$}
41
+ # rails.views = %r{^app/views/(.+)/.*\.(erb|haml|slim)$}
42
+ #
43
+ # watch(rails.app) { |m| rspec.spec.(m[1]) }
44
+ # watch(rails.views_n_layouts) { |m| rspec.spec.("#{m[1]}#{m[2]}") }
45
+ # watch(rails.controllers) do |m|
46
+ # [
47
+ # rspec.spec.("routing/#{m[1]}_routing"),
48
+ # rspec.spec.("controllers/#{m[1]}_controller"),
49
+ # rspec.spec.("acceptance/#{m[1]}")
50
+ # ]
51
+ # end
52
+
53
+ # watch(rails.spec_support) { rspec.spec_dir }
54
+ # watch(rails.spec_helper) { rspec.spec_dir }
55
+ # watch(rails.routes) { "spec/routing" }
56
+ # watch(rails.app_controller) { "spec/controllers" }
57
+
58
+ # Capybara features specs
59
+ # watch(rails.views) { |m| rspec.spec.("features/#{m[1]}") }
60
+
61
+ # Turnip features and steps
62
+ watch(%r{^spec/acceptance/(.+)\.feature$})
63
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
64
+ Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
65
+ end
66
+
67
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 BroderickBrockman
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # Frigate
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'frigate'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install frigate
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/frigate/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+ # require 'rake/testtask'
3
+ require 'rspec/core/rake_task'
4
+
5
+ task :default => :spec
6
+ RSpec::Core::RakeTask.new
7
+
8
+ # task :default => [:test]
9
+ # Rake::TestTask.new(:test) do |test|
10
+ # test.libs << 'test'
11
+ # test.test_files = FileList['test/*_test.rb']
12
+ # test.verbose = true
13
+ # end
data/frigate.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'frigate/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "frigate"
8
+ spec.version = Frigate::VERSION
9
+ spec.authors = ['Vladislav Pauk']
10
+ spec.email = ['vladislavpauk@gmail.com']
11
+ spec.summary = %q{ thinking about it }
12
+ spec.description = %q{still thinking about it}
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.7'
22
+ spec.add_development_dependency 'rake', '~> 10.0'
23
+ # spec.add_development_dependency 'rspec', '~> 3.1.0'
24
+ # spec.add_development_dependency 'guard-rspec', '~> 4.4.2'
25
+ # spec.add_development_dependency 'rails', '~> 4.1'
26
+ # spec.add_development_dependency 'sqlite3', '~> 1.3.10'
27
+ # spec.add_development_dependency 'database_cleaner', '~> 1.3.0'
28
+ spec.add_dependency 'activemodel', '~> 4.1'
29
+ spec.add_dependency 'activesupport', '~> 4.1'
30
+ spec.add_dependency 'hashie', '~> 3.3.2'
31
+ end
@@ -0,0 +1,94 @@
1
+ module Frigate
2
+ module Form
3
+ # Uses to define a form association with properties as Frigate::Form::Property
4
+ class Association
5
+ class << self
6
+ # defines property for association
7
+ # @param [Symbol] name
8
+ # @param [Hash] options
9
+ def property(name, options={})
10
+ @properties ||= {}
11
+ @properties[name.to_sym] = options
12
+ end
13
+
14
+ # defines association (kinda property with properties) for association
15
+ # @param [Symbol] name
16
+ # @param [Hash] options
17
+ # @param [Proc] block
18
+ def has_one(name, options={}, &block)
19
+ @associations ||= {}
20
+ @associations[name.to_sym] = options.merge({ block: block })
21
+ end
22
+
23
+ # gets just options for defined properties
24
+ # @example properties hash
25
+ # { skype: { validates: { presence: true }, another_option: another_option_hash } }
26
+ def properties
27
+ @properties.deep_dup || {}
28
+ end
29
+
30
+ # gets just options for defined associations
31
+ # @example associations hash
32
+ # { some_name: { block: <Proc.new instance> }
33
+ def associations
34
+ @associations.deep_dup || {}
35
+ end
36
+ end
37
+
38
+ attr_reader :name, :opts, :properties, :associations, :root, :parent
39
+ # @param [Symbol] name
40
+ # @param [Hash] opts
41
+ def initialize(name, root, parent, opts = {})
42
+ @name, @root, @parent, @opts = name, root, parent, opts
43
+ @properties, @associations = [], []
44
+
45
+ exec_opts_block
46
+ process_properties
47
+ process_associations
48
+ end
49
+
50
+ # gets errors of association
51
+ # @return [ActiveModel::Errors]
52
+ def errors
53
+ @errors ||= ActiveModel::Errors.new(self)
54
+ end
55
+
56
+ # checks validness of association properties
57
+ def valid?
58
+ errors.messages.empty?
59
+ end
60
+
61
+ # validates association properties
62
+ def validate
63
+ properties.each { |_prop| errors.add(_prop.name, _prop.errors[:value]) unless _prop.valid? }
64
+ end
65
+
66
+ private
67
+
68
+ # exec_opts_block
69
+ def exec_opts_block
70
+ singleton_class.instance_exec &@opts.delete(:block)
71
+ end
72
+
73
+ # initializes declared associations
74
+ def process_associations
75
+ singleton_class.associations.each do |_assoc_name, _assoc_options|
76
+ _assoc = Association.new(_assoc_name, root, self, _assoc_options)
77
+ @associations << _assoc
78
+ define_singleton_method(_assoc.name) { _assoc }
79
+ end
80
+ end
81
+
82
+ # initializes declared properties
83
+ def process_properties
84
+ singleton_class.properties.each do |_prop_name, _prop_options|
85
+ _prop = Property.new(_prop_name, root, self, _prop_options)
86
+ @properties << _prop
87
+ define_singleton_method(_prop.name) { _prop }
88
+ end
89
+ end
90
+
91
+ # TODO add am::verifications
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,141 @@
1
+ require 'frigate/form/property'
2
+ require 'frigate/form/association'
3
+ require 'frigate/form/synchronizer'
4
+ module Frigate
5
+ module Form
6
+ #
7
+ # Is used for model validation outside of model
8
+ #
9
+ # @example A form for User class
10
+ # class UserForm < Frigate::Form::Base
11
+ # property :email, validates: { presence: true }
12
+ # has_one :user_profile do
13
+ # property :first_name, validates: { presence: true }
14
+ # property :last_name
15
+ # property :skype
16
+ # end
17
+ # end
18
+ #
19
+ # class UserFormCustom < Frigate::Form::Base
20
+ # property :email, validates: { presence: true },
21
+ # validate: [
22
+ # Proc.new { error(:invalid) unless value =~ /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i },
23
+ # ]
24
+ # has_one :user_profile do
25
+ # property :first_name, validates: { presence: true }
26
+ # property :last_name
27
+ # property :skype
28
+ # end
29
+ # end
30
+ #
31
+ # class UserFormTree < Frigate::Form::Base
32
+ # property :email
33
+ # has_one :user_profile do
34
+ # property :first_name
35
+ # property :last_name
36
+ # property :skype
37
+ # has_one :user_profile_passport do
38
+ # property :number
39
+ # property :country
40
+ # property :city
41
+ # end
42
+ # end
43
+ # end
44
+ #
45
+ # user = User.new
46
+ # user.build_user_profile
47
+ # user_form = UserForm.new(user)
48
+ # user_form.valid? # returns false
49
+ # user_form.validate({email: 'z1@zzz.zz', user_profile: {first_name:'Alpha', last_name:'Omega'}}) # returns true
50
+ # user_form.valid? # returns true
51
+ #
52
+ # @author Vladislav Pauk <vladislavpauk@gmail.com>
53
+ #
54
+ class Base
55
+ class << self
56
+ # gets just options for defined properties
57
+ # @example properties hash
58
+ # { skype: { validates: { presence: true }, another_option: another_option_hash } }
59
+ def properties
60
+ @properties.deep_dup || {}
61
+ end
62
+
63
+ # gets just options for defined associations
64
+ # @example associations hash
65
+ # { some_name: { block: <Proc.new instance> }
66
+ def associations
67
+ @associations.deep_dup || {}
68
+ end
69
+
70
+ # defines property (root) of form/base
71
+ # @param [Symbol] name
72
+ # @param [Hash] options
73
+ def property(name, options={})
74
+ @properties ||= {}
75
+ @properties[name.to_sym] = options
76
+ end
77
+
78
+ # defines association (kinda property with properties)(root as well) of form/base
79
+ # @param [Symbol] name
80
+ # @param [Hash] options
81
+ # @param [Proc] block
82
+ def has_one(name, options={}, &block)
83
+ @associations ||= {}
84
+ @associations[name.to_sym] = options.merge({ block: block })
85
+ end
86
+ end
87
+
88
+ attr_reader :model, :properties, :associations
89
+ delegate :sync_with_model, :sync_properties_with_model_or_params, :sync_errors, to: :@syncronizator
90
+
91
+ # Method of initialization of Frigate::Form class
92
+ # @param [Object] model
93
+ def initialize(model, opts={})
94
+ @syncronizator = opts[:contract] ? Synchronizer::Contract.new(self) : Synchronizer::Form.new(self)
95
+ @model, @properties, @associations = model, [], []
96
+
97
+ process_properties
98
+ process_associations
99
+ end
100
+
101
+ # Initializes errors instance variable of ActiveModel::Errors type
102
+ # @return [ActiveModel::Errors] return errors
103
+ def errors
104
+ @errors ||= ActiveModel::Errors.new(self)
105
+ end
106
+
107
+ # Validates form with params or model properties
108
+ def validate(*args)
109
+ sync_properties_with_model_or_params(*args)
110
+ sync_errors
111
+ valid?
112
+ end
113
+
114
+ # returns true if are there any errors messages in form errors
115
+ # @return [Boolean] return true if form model is valid
116
+ def valid?
117
+ errors.messages.empty?
118
+ end
119
+
120
+ private
121
+
122
+ # initializes declared associations
123
+ def process_associations
124
+ self.class.associations.each do |_assoc_name, _assoc_options|
125
+ _assoc = Association.new(_assoc_name, self, self, _assoc_options)
126
+ @associations << _assoc
127
+ define_singleton_method(_assoc.name) { _assoc }
128
+ end
129
+ end
130
+
131
+ # initializes declared properties
132
+ def process_properties
133
+ self.class.properties.each do |_prop_name, _prop_options|
134
+ _prop = Property.new(_prop_name, self, self, _prop_options)
135
+ @properties << _prop
136
+ define_singleton_method(_prop.name) { _prop }
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,40 @@
1
+ module Frigate
2
+ module Form
3
+ # Uses to define a form property
4
+ class Property
5
+ attr_accessor :name, :options, :value, :root, :parent
6
+
7
+ include ActiveModel::Validations
8
+
9
+ # @param [Symbol] name
10
+ # @param [Hash] options
11
+ def initialize(name, root, parent, options)
12
+ @name, @root, @parent, @options = name, root, parent, options
13
+
14
+ set_validations
15
+ set_custom_validations
16
+ end
17
+
18
+ private
19
+
20
+ def set_validations
21
+ validations = options.delete(:validates)
22
+ singleton_class.class_eval { validates :value, validations } if validations
23
+ true
24
+ end
25
+
26
+ def set_custom_validations
27
+ validations = options.delete(:validate)
28
+ validations.is_a?(Array) and validations.each do |validation|
29
+ singleton_class.class_eval { validate &validation }
30
+ end
31
+ end
32
+
33
+ def add_error(name)
34
+ errors.add(:value, name)
35
+ end
36
+
37
+ alias_method :error, :add_error
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,22 @@
1
+ module Frigate
2
+ module Form
3
+ # Serves for synchronization form properties with model attributes/properties
4
+ module Synchronizer
5
+ # Base class for Frigate::Form::Base synchronizations
6
+ # It justs abstract class which has two methods
7
+ # * sync form with model
8
+ # * sync properties errors into form errors
9
+ class Base < Fundamental
10
+ # synchronizes form with model
11
+ def sync_with_model
12
+ raise NotImplementedError
13
+ end
14
+
15
+ # synchronizes form properties (associations:properties) errors with general form errors
16
+ def sync_errors
17
+ raise NotImplementedError
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,75 @@
1
+ module Frigate
2
+ module Form
3
+ # Serves for synchronization form properties with model attributes/properties
4
+ module Synchronizer
5
+ # A syncronizator between form properties and model properties
6
+ class Basic < Base
7
+ # A class for synchronization model with params
8
+ class ModelSynchronizer < Fundamental
9
+ # Synchronizes given model with form properties and associations:properties
10
+ # @param [Hash] ops
11
+ def sync_with_model(opts={})
12
+ sync_properties
13
+ sync_associations
14
+ save_model if opts[:save]
15
+ end
16
+
17
+ private
18
+
19
+ def save_model
20
+ form.model.save!
21
+ end
22
+
23
+ def sync_associations
24
+ _sync_associations(form, form.model)
25
+ end
26
+
27
+ def sync_properties
28
+ _sync_properties(form, form.model)
29
+ end
30
+
31
+ def _sync_associations(f_ctx, m_ctx)
32
+ f_ctx.associations.each do |_assoc|
33
+ n_m_ctx = m_ctx.send(_assoc.name.to_sym)
34
+ if m_ctx.is_a?(ActiveRecord::Base) and n_m_ctx.nil?
35
+ m_ctx.send("build_#{_assoc.name}")
36
+ end
37
+ _assoc.properties.each do |_prop|
38
+ _sync_properties(_assoc, n_m_ctx)
39
+ end
40
+ _sync_associations(_assoc, n_m_ctx)
41
+ end
42
+ end
43
+
44
+ def _sync_properties(f_ctx, m_ctx)
45
+ f_ctx.properties.each do |_prop|
46
+ m_ctx.send("#{_prop.name}=", _prop.value) unless _prop.value.nil?
47
+ end
48
+ end
49
+ end
50
+
51
+ # Synchronizes given params with given model
52
+ # @param [Hash] opts
53
+ # @return [Boolean] true
54
+ def sync_with_model(opts={})
55
+ ModelSynchronizer.new(form).sync_with_model(opts)
56
+ end
57
+
58
+ # Synchronizes properties errors with form errors
59
+ # @return [Boolean]
60
+ def sync_errors
61
+ form.properties.each { |_prop| form.errors.add(_prop.name, _prop.errors[:value]) unless _prop.valid? }
62
+ form.associations.each do |_assoc|
63
+ _assoc.properties.each do |_prop|
64
+ form.errors.add("#{_assoc.name}.#{_prop.name}", _prop.errors[:value]) unless _prop.valid?
65
+ end
66
+ end
67
+ end
68
+
69
+ def sync_properties_with_model_or_params
70
+ raise NotImplementedError
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,46 @@
1
+ module Frigate
2
+ module Form
3
+ # Serves for synchronization form properties with model attributes/properties
4
+ module Synchronizer
5
+ # Synchronizes form properties with model properties
6
+ class Contract < Basic # TODO: tree-association support, as form does
7
+ # Synchronizes given model's attributes with form properties and associations:properties
8
+ def sync_properties_with_model_or_params
9
+ #
10
+ # sync model properties with form properties
11
+ #
12
+ form.properties.each do |_prop|
13
+ if form.model.respond_to?(_prop.name.to_sym)
14
+ _prop.value = form.model.send(_prop.name.to_sym)
15
+ else
16
+ raise StandardError.new('form model does not have %s property' % [_prop.name])
17
+ end
18
+ end
19
+ #
20
+ # sync model associations' properties with form associations' properties
21
+ #
22
+ form.associations.each do |_a|
23
+ if form.model.respond_to?(_a.name.to_sym) and !form.model.send(_a.name.to_sym).nil?
24
+ _a.properties.each do |_p|
25
+ if form.model.send(_a.name.to_sym).respond_to?(_p.name.to_sym)
26
+ _p.value = form.model.send(_a.name.to_sym).send(_p.name.to_sym)
27
+ else
28
+ _err_msg = 'form model %s association does not have %s property' % [_a.name, _p.name]
29
+ raise StandardError.new(_err_msg)
30
+ end
31
+ end
32
+ else
33
+ if form.model.respond_to?(_a.name.to_sym)
34
+ _err_msg = 'form model %s association is nil' % [_a.name]
35
+ raise StandardError.new(_err_msg)
36
+ else
37
+ _err_msg = 'form model does not have %s association' % [_a.name]
38
+ raise StandardError.new(_err_msg)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,40 @@
1
+ module Frigate
2
+ module Form
3
+ # Serves for synchronization form properties with model attributes/properties
4
+ module Synchronizer
5
+ # Synchronizes form properties with given params
6
+ class Form < Basic
7
+ # It's just extracted method *sync_properties_with_model_or_params* into this class
8
+ class ParamsToPropertiesSynchronizer < Fundamental
9
+ # Synchronizes given params with form properties and associations:properties
10
+ # @param [Hash] params
11
+ def sync_params_with_properties(params)
12
+ process_params(params, form)
13
+ end
14
+
15
+ private
16
+
17
+ def process_params(params, ctx)
18
+ params.each do |_p_n, _p_v|
19
+ if _p_v.is_a?(Hash)
20
+ process_params(_p_v, ctx.send(_p_n.to_sym))
21
+ else
22
+ sync_properties(_p_n, _p_v, ctx)
23
+ end
24
+ end
25
+ end
26
+
27
+ def sync_properties(p_n, p_v, ctx)
28
+ ctx.properties.each { |_p| _p.value = p_v if p_n.to_sym == _p.name.to_sym }
29
+ end
30
+ end
31
+
32
+ # Synchronizes given params with form properties and associations:properties
33
+ # @param [Hash] params
34
+ def sync_properties_with_model_or_params(params)
35
+ ParamsToPropertiesSynchronizer.new(form).sync_params_with_properties(params)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end