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
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