ciesta 0.1.1 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e648671453a91e2f62c7db71603ad9dbcea1606c2d5404fca7708a54a9a177a
4
- data.tar.gz: 1067bcb0dc3b31f64090981b2ed4e9c0a102b02fd9aedca04c99114cb10ae8e4
3
+ metadata.gz: fa6bcec524ba6b6e11a71bd2fa2852c805f4a2359375a6aeba89fb627a9b8235
4
+ data.tar.gz: ee3c19951c78d75b8adc45296277b3610e8fd7ca8c93ea4a99c60bfa2d6d0613
5
5
  SHA512:
6
- metadata.gz: 4b2f569ade3113c3060f38bcecbc84063dcab3821d1237b0d6f95979dfdafd19ba3e5ca6590d635eb24726ef699d9399305677c95539b1fadd9b85e39cddc29c
7
- data.tar.gz: 10aff7f55262f29b3983167f76f76fadb50e2a1f067b29e6a778e8204af173ac7b4abcbc299596f2cde405e71f9404842cd0dbe32efeeb2e77d22a9afe3e1339
6
+ metadata.gz: 8780acfc8511f0e275a67643ea470e4150f7c16991b841c17353b39788a892ab3d4716bc56cbfd759cefe81555ba351141e7ce13b5427d0b70a67259824f0adf
7
+ data.tar.gz: 7bc5a4bbeb0549e329f11a6f810b2369debf9955d0fa276cd92ac40cf264f5685147362676d344aacd613e4bfa833cc7f5b2de518125f02367ff7e0bf1099861
@@ -0,0 +1,2 @@
1
+ ruby:
2
+ config_file: .rubocop.yml
@@ -0,0 +1,14 @@
1
+ inherit_gem:
2
+ rubocop-config-umbrellio: lib/rubocop.rails.yml
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 2.1
6
+ Exclude:
7
+ - db/schema.rb
8
+ - ciesta.gemspec
9
+
10
+ Metrics/LineLength:
11
+ IgnoredPatterns: ['#.*']
12
+
13
+ Rails/SaveBang:
14
+ Enabled: false
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
- source 'https://rubygems.org'
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
2
4
 
3
5
  git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
6
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ciesta (0.1.0)
4
+ ciesta (0.1.1)
5
5
  dry-types (~> 0.12.1)
6
6
  dry-validation (~> 0.11.1)
7
7
 
data/README.md CHANGED
@@ -1,18 +1,24 @@
1
1
  # Ciesta
2
2
 
3
- [![Coverage Status](https://coveralls.io/repos/github/nulldef/ciesta/badge.svg?branch=master)](https://coveralls.io/github/nulldef/ciesta?branch=master)
4
3
  [![Build Status](https://travis-ci.org/nulldef/ciesta.svg?branch=master)](https://travis-ci.org/nulldef/ciesta)
4
+ [![Coverage Status](https://coveralls.io/repos/github/nulldef/ciesta/badge.svg?branch=master&rand=22)](https://coveralls.io/github/nulldef/ciesta?branch=master)
5
+ [![Gem Version](https://badge.fury.io/rb/ciesta.svg)](https://badge.fury.io/rb/ciesta)
5
6
 
6
7
  Create simple form objects
7
8
 
8
9
  Supported Ruby 2.2.0+
9
10
 
11
+ You should keep it in mind that here uses [dry-validation](https://github.com/dry-rb/dry-validation) and [dry-types](https://github.com/dry-rb/dry-types) for validation and typification respectively.
12
+
10
13
  - [Installation](#installation)
11
14
  - [Usage](#usage)
12
- - [Basic usage](#basic-usage)
13
- - [Assign values](#assign-values)
14
- - [Syncing attributes](#syncing-attributes)
15
- - [Types](#types)
15
+ - [Basic case](#basic-case)
16
+ - [Syncing](#syncing)
17
+ - [Validation](#validation)
18
+ - [Advanced declaring fields](#advanced-declaring-fields)
19
+ - [Types](#types)
20
+ - [Default value](#default-value)
21
+ - [Mass updating values](#mass-updating-values)
16
22
  - [Contributing](#contributing)
17
23
  - [License](#license)
18
24
 
@@ -21,7 +27,7 @@ Supported Ruby 2.2.0+
21
27
  Add this line to your application's Gemfile:
22
28
 
23
29
  ```ruby
24
- gem 'ciesta'
30
+ gem "ciesta"
25
31
  ```
26
32
 
27
33
  And then execute:
@@ -30,17 +36,53 @@ And then execute:
30
36
 
31
37
  Or install it yourself as:
32
38
 
33
- $ gem install statum
39
+ $ gem install ciesta
34
40
 
35
- ## Usage
36
41
 
37
- ### Basic usage
42
+ ## Usage
38
43
 
39
- For validation it uses [dry-validation](https://github.com/dry-rb/dry-validation) under the hood. You can use all features of validation provided there.
44
+ ### Basic case
45
+ Just imageine that we have a user object with `name` and `age` attributes:
40
46
 
41
47
  ```ruby
42
48
  User = Struct.new(:name, :age)
43
49
 
50
+ user = User.new(nil, nil)
51
+ ```
52
+ And we need to save new values and update and we will use simple form object:
53
+
54
+ ```ruby
55
+ class Form < Ciesta::Form
56
+ field :name
57
+ field :age
58
+ end
59
+
60
+ form = Form.new(user)
61
+ ```
62
+
63
+ ```ruby
64
+ form.name = "John"
65
+ form.age = 33
66
+ form.sync!
67
+
68
+ user.name # => "John"
69
+ user.age # => 33
70
+ ```
71
+
72
+ ### Syncing
73
+ You can pass a block to sync method to do some stuff with object after syncing.
74
+
75
+ ```ruby
76
+ form.sync! do |user|
77
+ user.make_happy!
78
+ end
79
+ ```
80
+ Both methods `sync` and `sync!` are provides this DSL.
81
+
82
+ ### Validation
83
+ There we want to validate incoming values. We should use `validate` method:
84
+
85
+ ```ruby
44
86
  class Form < Ciesta::Form
45
87
  field :name
46
88
  field :age
@@ -50,58 +92,75 @@ class Form < Ciesta::Form
50
92
  required(:age).filled(gt?: 18)
51
93
  end
52
94
  end
95
+
96
+ form = Form.new(user)
53
97
  ```
54
98
 
55
- And use it
99
+ Trying to sync with invalid form will raise `Ciesta::FormNotValid` error.
56
100
 
57
101
  ```ruby
58
- user = User.new("John", nil)
59
- form = Form.new(user)
60
- form.valid?(age: 10) # => false
61
- form.valid?(age: 20) # => true
102
+ form.age = 15
103
+ form.valid? # => false
104
+ form.sync! # => raises Ciesta::FormNotValid
105
+ form.errors # => { age: ["must be greater than 18"] }
106
+ ...
107
+ form.age = 42
108
+ form.sync! # => true
109
+
110
+ user.age # => 42
62
111
  ```
63
112
 
64
- ### Assign values
113
+ ### Advanced declaring fields
65
114
 
66
- You can assign values to form with two methods `assign!` and `assign`
115
+ #### Types
116
+ You can define a type of the field using `Ciesta::Types` namespace.
67
117
 
68
118
  ```ruby
69
- class Form < Ciesta::Form
70
- field :bar
71
- end
72
-
73
- form.assign!(foo: 1, bar: 2) # => raises Ciesta::FieldNotDefined
119
+ field :age, type: Ciesta::Types::Coercible::Int
74
120
  ...
75
- form.assign(foo: 1, bar: 2)
76
- form.foo # => 1
121
+ form.age = "42"
122
+ form.age # => 42
77
123
  ```
124
+ Default type is `Ciesta::Types::Any`.
78
125
 
79
- You can pass attributes directly to `valid?` method. In this case `assing` method will be used.
126
+ #### Default value
127
+ If your attribute wasn't set yet but value already is in use, you can set `default` option to avoid some kind of exceptions.
80
128
 
81
- ### Syncing attributes
129
+ ```ruby
130
+ field :age, default: 42
131
+ ...
132
+ form.age # => 42
133
+ ```
82
134
 
83
- You can use methods `sync` and `sync!` for mapping form values to the object. The difference is only that the second one will raise error if form is invalid.
135
+ Default value can also be a `Proc`, wich will executed in object context.
84
136
 
85
137
  ```ruby
86
- form.valid?(age: 10)
87
- form.sync! # => raises Ciesta::NotValid
88
- form.sync # => returns nil
138
+ class User
139
+ def default_age
140
+ 42
141
+ end
142
+ end
89
143
  ```
90
144
 
91
- ### Types
145
+ ```ruby
146
+ field :age, default: -> { default_age }
147
+ ...
148
+ form.age # => 42
149
+ ```
92
150
 
93
- You can provide the type of each field for ciercing or checking one. All types provided by [dry-types](https://github.com/dry-rb/dry-types) but in gem's namespace.
151
+ ## Mass updating values
152
+ There are exists two methods for mass update form fields: `assign` and `assign!`.
94
153
 
95
154
  ```ruby
96
- class Form < Ciesta::Form
97
- field :foo, type: Ciesta::Types::Coercible::String
98
- end
99
-
100
- # ...
101
- form.assign(foo: 1) # => true
102
- form.foo # => "1"
155
+ form.assign!(name: "Neo", age: 30)
156
+ form.sync!
157
+ ...
158
+ user.name # => "Neo"
159
+ user.age # => 30
103
160
  ```
104
161
 
162
+ `assign!` method will raise `Ciesta::FieldNotDefined` error if one of passed attribute is not exists in the form.
163
+
105
164
  ## Contributing
106
165
 
107
166
  Bug reports and pull requests are welcome on GitHub at [https://github.com/nulldef/ciesta](https://github.com/nulldef/ciesta).
data/Rakefile CHANGED
@@ -1,5 +1,7 @@
1
- require 'bundler/gem_tasks'
2
- require 'rspec/core/rake_task'
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require 'bundler/setup'
4
- require 'ciesta'
4
+ require "bundler/setup"
5
+ require "ciesta"
5
6
 
6
7
  # require "pry"
7
8
  # Pry.start
8
9
 
9
- require 'irb'
10
+ require "irb"
10
11
  IRB.start(__FILE__)
@@ -1,41 +1,43 @@
1
1
 
2
- lib = File.expand_path('../lib', __FILE__)
2
+ # frozen_string_literal: true
3
+
4
+ lib = File.expand_path("../lib", __FILE__)
3
5
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'ciesta/version'
6
+ require "ciesta/version"
5
7
 
6
8
  Gem::Specification.new do |spec|
7
- spec.name = 'ciesta'
9
+ spec.name = "ciesta"
8
10
  spec.version = Ciesta::VERSION
9
- spec.authors = ['Alexey']
10
- spec.email = ['alex.coder1@gmail.com']
11
+ spec.authors = ["Alexey"]
12
+ spec.email = ["alex.coder1@gmail.com"]
11
13
 
12
- spec.summary = 'Create form objects easy'
13
- spec.description = 'Gem for creating and using form object'
14
- spec.homepage = 'https://github.com/nulldef/ciesta'
15
- spec.license = 'MIT'
14
+ spec.summary = "Create form objects easy"
15
+ spec.description = "Gem for creating and using form object"
16
+ spec.homepage = "https://github.com/nulldef/ciesta"
17
+ spec.license = "MIT"
16
18
 
17
19
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
20
  # to allow pushing to a single host or delete this section to allow pushing to any host.
19
21
  if spec.respond_to?(:metadata)
20
22
  # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
21
23
  else
22
- raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
24
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
25
  end
24
26
 
25
27
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
26
28
  f.match(%r{^(test|spec|features)/})
27
29
  end
28
- spec.bindir = 'exe'
30
+ spec.bindir = "exe"
29
31
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
- spec.require_paths = ['lib']
32
+ spec.require_paths = ["lib"]
31
33
  spec.required_ruby_version = ">= 2.0"
32
34
 
33
- spec.add_dependency 'dry-types', '~> 0.12.1'
34
- spec.add_dependency 'dry-validation', '~> 0.11.1'
35
+ spec.add_dependency "dry-types", "~> 0.12.1"
36
+ spec.add_dependency "dry-validation", "~> 0.11.1"
35
37
 
36
- spec.add_development_dependency 'bundler', '~> 1.16'
37
- spec.add_development_dependency 'coveralls', '~> 0.8'
38
- spec.add_development_dependency 'pry', '~> 0.11'
39
- spec.add_development_dependency 'rake', '~> 10.0'
40
- spec.add_development_dependency 'rspec', '~> 3.0'
38
+ spec.add_development_dependency "bundler", "~> 1.16"
39
+ spec.add_development_dependency "coveralls", "~> 0.8"
40
+ spec.add_development_dependency "pry", "~> 0.11"
41
+ spec.add_development_dependency "rake", "~> 10.0"
42
+ spec.add_development_dependency "rspec", "~> 3.0"
41
43
  end
@@ -1,11 +1,16 @@
1
- require 'dry-types'
2
- require 'dry-validation'
3
- require 'ciesta/version'
4
- require 'ciesta/types'
5
- require 'ciesta/validator'
6
- require 'ciesta/errors'
7
- require 'ciesta/field'
8
- require 'ciesta/form'
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-types"
4
+ require "dry-validation"
5
+ require "ciesta/delegator"
6
+ require "ciesta/version"
7
+ require "ciesta/field_list"
8
+ require "ciesta/syncer"
9
+ require "ciesta/types"
10
+ require "ciesta/validator"
11
+ require "ciesta/errors"
12
+ require "ciesta/field"
13
+ require "ciesta/form"
9
14
 
10
15
  module Ciesta
11
16
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Simple module for delegate methods
4
+ module Ciesta::Delegator
5
+ # Delegates methods to object
6
+ #
7
+ # @param [Array<String, Symbol>] methods Methods to delegate
8
+ # @param [Symbol] to Method's name delegate to
9
+ def delegate(*methods, to:)
10
+ methods.each do |name|
11
+ method_def = [
12
+ "def #{name}(*args, &block)",
13
+ " if !#{to}.nil?",
14
+ " #{to}.#{name}(*args, &block)",
15
+ " end",
16
+ "end",
17
+ ].join(";")
18
+
19
+ module_eval(method_def)
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ciesta
4
+ # Error class for error about violating constraints
2
5
  ViolatesConstraints = Class.new(ArgumentError)
3
- NotValid = Class.new(StandardError)
6
+
7
+ # Error for invalid object
8
+ FormNotValid = Class.new(StandardError)
9
+
10
+ # Error for missing field definition
4
11
  FieldNotDefined = Class.new(NoMethodError)
5
12
  end
@@ -1,27 +1,78 @@
1
- module Ciesta
2
- class Field
3
- DEFAULT_TYPE = Ciesta::Types::Any
1
+ # frozen_string_literal: true
4
2
 
5
- attr_accessor :name, :type
3
+ # Class for storing form field
4
+ #
5
+ # @attr_reader [Symbol] name Field name
6
+ # @attr_reader [Ciesta::Types::Declaration] type Field type
7
+ class Ciesta::Field
8
+ # Default type when another one is not passed
9
+ DEFAULT_TYPE = Ciesta::Types::Any
6
10
 
7
- def initialize(name, options)
8
- self.name = name.to_sym
9
- self.type = options.delete(:type) || DEFAULT_TYPE
10
- self.value = options.delete(:default)
11
- end
11
+ attr_reader :name, :type
12
12
 
13
- def value
14
- current_value
15
- end
13
+ # Constructor
14
+ #
15
+ # @param [Symbol] name Name of the field
16
+ # @param [Hash] options Field's options
17
+ # @option [Ciesta::Types::Definition] :type Type of value stored in this field
18
+ # @option [Proc, Lambda, any] :default Default value for this field
19
+ def initialize(name, options)
20
+ @name = name.to_sym
21
+ @type = options.delete(:type) || DEFAULT_TYPE
22
+ @default = options.delete(:default)
23
+ end
16
24
 
17
- def value=(val)
18
- self.current_value = type[val]
19
- rescue Dry::Types::ConstraintError
20
- raise ViolatesConstraints, "#{current_value} is not a #{type.name}"
21
- end
25
+ # Sets a new value for field
26
+ #
27
+ # @param [any] val Value
28
+ #
29
+ # @raise Ciesta::ViolatesConstraints
30
+ def value=(val)
31
+ @value = type[val]
32
+ @was_set = true
33
+ rescue Dry::Types::ConstraintError
34
+ raise Ciesta::ViolatesConstraints, "#{val} is not a #{type.name}"
35
+ end
36
+
37
+ # Returns current value
38
+ #
39
+ # @return [any]
40
+ def value
41
+ return @value if @was_set
22
42
 
23
- private
43
+ @value || default
44
+ end
24
45
 
25
- attr_accessor :current_value
46
+ # Binds current field to object
47
+ #
48
+ # @api private
49
+ # @param [Object] obj Object to mapping to
50
+ def bind(obj)
51
+ @binding = obj
52
+ end
53
+
54
+ private
55
+
56
+ # Returns typed default value for field
57
+ #
58
+ # @api private
59
+ # @return [any]
60
+ # @raise Ciesta::ViolatesConstraints
61
+ def default
62
+ type[raw_default]
63
+ rescue Dry::Types::ConstraintError
64
+ raise Ciesta::ViolatesConstraints, "#{def_value} is not a #{type.name}"
65
+ end
66
+
67
+ # Returns raw default value
68
+ #
69
+ # @api private
70
+ # @return [any]
71
+ def raw_default
72
+ if @default.respond_to?(:call) && @binding
73
+ @binding.instance_exec(&@default)
74
+ else
75
+ @default
76
+ end
26
77
  end
27
78
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ # List of object fields
4
+ #
5
+ # @api private
6
+ # @attr_reader [Hash<Symbol, Ciesta::Field>] list Field list
7
+ class Ciesta::FieldList
8
+ # Constructor
9
+ def initialize
10
+ @list = {}
11
+ end
12
+
13
+ # Adds new field to list
14
+ #
15
+ # @param [Ciesta::Field] field New field
16
+ def <<(field)
17
+ list[field.name] = field
18
+ end
19
+
20
+ # Getting field by name
21
+ #
22
+ # @param [Symbol] name Field name
23
+ #
24
+ # @return [Ciesta::Field]
25
+ def [](name)
26
+ list[name.to_sym].value
27
+ end
28
+
29
+ # Setting field value
30
+ #
31
+ # @param [Symbol] name Field name
32
+ # @param [any] value Field value
33
+ def []=(name, value)
34
+ list[name.to_sym].value = value
35
+ end
36
+
37
+ # Mass assign values to fields
38
+ #
39
+ # @param [Hash<Symbol, any>] attributes Attributes
40
+ #
41
+ # @raise Ciesta::FieldNotDefined
42
+ # @return [Boolean]
43
+ def assign!(attributes)
44
+ attributes.each { |name, value| self[name] = value }
45
+ true
46
+ rescue NoMethodError => e
47
+ raise Ciesta::FieldNotDefined, "Field #{e.name} is not specified"
48
+ end
49
+
50
+ # Mass assign values to fields
51
+ #
52
+ # @param [Hash<Symbol, any>] attributes Attributes
53
+ #
54
+ # @return [Boolean]
55
+ def assign(attributes)
56
+ attributes = attributes.keep_if { |key| keys.include?(key) }
57
+ assign!(attributes) rescue false
58
+ end
59
+
60
+ # Getting all field names
61
+ #
62
+ # @return [Array<Symbol>]
63
+ def keys
64
+ list.keys
65
+ end
66
+
67
+ # Getting all field values
68
+ #
69
+ # @return [Hash<Symbol, any>]
70
+ def attributes
71
+ list.values.each_with_object({}) { |field, mem| mem[field.name] = field.value }
72
+ end
73
+
74
+ # Iterate over all fields
75
+ #
76
+ # @param [Block] block Block to iterate
77
+ def each
78
+ list.each { |name, field| yield(name, field.value) }
79
+ end
80
+
81
+ private
82
+
83
+ attr_reader :list
84
+ end
@@ -1,91 +1,124 @@
1
- module Ciesta
2
- class Form
3
- def self.field(name, options = {})
1
+ # frozen_string_literal: true
2
+
3
+ # Main form class
4
+ #
5
+ # @attr_reader [Object] object Object of form
6
+ class Ciesta::Form
7
+ extend Ciesta::Delegator
8
+
9
+ # @!method assign
10
+ # @!method assign!
11
+ # @!method attributes
12
+ # @see Ciesta::FieldList
13
+ delegate :assign, :assign!, :attributes, to: :fields
14
+
15
+ # @!method sync!
16
+ # @!method sync
17
+ # @see Ciesta::Syncer
18
+ delegate :sync, to: :syncer
19
+
20
+ # @!method errors
21
+ # @see Ciesta::Validator
22
+ delegate :errors, to: :validator
23
+
24
+ class << self
25
+ # Declare new form field
26
+ #
27
+ # @param [Symbol] name Field name
28
+ # @param [Hash] options Options
29
+ # @option (see Ciesta::Field)
30
+ def field(name, options = {})
4
31
  name = name.to_sym
5
- fields[name] ||= Ciesta::Field.new(name, options)
32
+ fields << Ciesta::Field.new(name, options)
6
33
 
7
- define_method(name) { self.class.fields[name].value }
8
- define_method("#{name}=") { |value| self.class.fields[name].value = value }
34
+ define_method(name) { fields[name] }
35
+ define_method("#{name}=") { |value| fields[name] = value }
9
36
  end
10
37
 
11
- def self.validate(&block)
38
+ # Declare rules for valudation
39
+ #
40
+ # @param [Block] block Block with validation rules
41
+ # @see http://dry-rb.org/gems/dry-validation
42
+ def validate(&block)
12
43
  validator.use(&block)
13
44
  end
14
45
 
15
- attr_accessor :object
16
-
17
- def initialize(object)
18
- self.object = object
19
-
20
- obj_values = fields.keys.each_with_object({}) do |key, mem|
21
- mem[key] = object.public_send(key)
22
- end
23
-
24
- assign(obj_values)
25
- end
26
-
27
- def valid?(params = nil)
28
- assign(params) if params
29
- validator.valid?(attributes)
30
- end
31
-
32
- def assign!(attributes)
33
- attributes.each { |key, value| send("#{key}=", value) }
34
- rescue NoMethodError => e
35
- raise Ciesta::FieldNotDefined, e.message
36
- end
37
-
38
- def assign(params)
39
- keys = fields.keys
40
- params.keep_if { |key, _value| keys.include?(key) }
41
- begin
42
- assign!(params)
43
- rescue StandardError
44
- nil
45
- end
46
+ # Returns field list
47
+ #
48
+ # @api private
49
+ # @return [Ciesta::FieldList]
50
+ def fields
51
+ @fields ||= Ciesta::FieldList.new
46
52
  end
47
53
 
48
- def errors
49
- validator.errors
54
+ # Returns form validator
55
+ #
56
+ # @api private
57
+ # @return [Ciesta::Validator]
58
+ def validator
59
+ @validator ||= Ciesta::Validator.new
50
60
  end
61
+ end
51
62
 
52
- def sync!
53
- raise Ciesta::NotValid, 'Form is not valid' unless errors.empty?
63
+ attr_accessor :object
54
64
 
55
- fields.each { |name, field| object.send("#{name}=", field.value) }
65
+ # Constructor
66
+ #
67
+ # @param [Object] object Object wich will be updated though this form
68
+ def initialize(object)
69
+ @object = object
56
70
 
57
- yield(object) if block_given?
58
- true
71
+ obj_values = fields.keys.each_with_object({}) do |key, mem|
72
+ mem[key] = object.public_send(key)
59
73
  end
60
74
 
61
- def sync
62
- sync!
63
- rescue StandardError
64
- nil
65
- end
75
+ assign(obj_values)
76
+ end
66
77
 
67
- private
78
+ # Checks if form is valid
79
+ #
80
+ # @param [Hash] params Attrubutes to assign before validation
81
+ #
82
+ # @return [Boolean]
83
+ def valid?(params = nil)
84
+ assign(params) if params
85
+ validator.valid?(attributes)
86
+ end
68
87
 
69
- def self.fields
70
- @fields ||= {}
71
- end
88
+ # Sync form attributes to object
89
+ #
90
+ # @param [Block] block Block wich will be yielded after synfing
91
+ #
92
+ # @raise Ciesta::FormNotValid
93
+ # @return [Boolean]
94
+ def sync!(&block)
95
+ raise Ciesta::FormNotValid, "Form is not valid" unless valid?
96
+ syncer.sync(&block)
97
+ end
72
98
 
73
- def self.validator
74
- @validator ||= Ciesta::Validator.new
75
- end
99
+ private
76
100
 
77
- def validator
78
- self.class.validator
79
- end
101
+ # Sync class for form
102
+ #
103
+ # @api private
104
+ # @return [Ciesta::Syncer]
105
+ def syncer
106
+ @syncer ||= Ciesta::Syncer.new(object, fields)
107
+ end
80
108
 
81
- def fields
82
- self.class.fields
83
- end
109
+ # Returns form validator
110
+ #
111
+ # @api private
112
+ # @see Ciesta::Form.validator
113
+ def validator
114
+ self.class.validator
115
+ end
84
116
 
85
- def attributes
86
- fields.values.each_with_object({}) do |field, mem|
87
- mem[field.name] = field.value
88
- end
89
- end
117
+ # Returns field list
118
+ #
119
+ # @api private
120
+ # @see Ciesta::Form.fields
121
+ def fields
122
+ self.class.fields
90
123
  end
91
124
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Class for syncing fields and object
4
+ #
5
+ # @api private
6
+ # @attr_reader [Object] object Form objecy
7
+ # @attr_reader [Ciesta::FieldList] fields Field list
8
+ class Ciesta::Syncer
9
+ # Constructor
10
+ #
11
+ # @param [Object] object Form objecr
12
+ # @param [Ciesta::FieldList] fields Field list
13
+ def initialize(object, fields)
14
+ @object = object
15
+ @fields = fields
16
+ end
17
+
18
+ # Sync attributes with objec
19
+ #
20
+ # @param [Block] block Block which will be yielded after syncing
21
+ #
22
+ # @return [Booelan]
23
+ def sync
24
+ fields.each { |name, value| object.send("#{name}=", value) }
25
+
26
+ yield(object) if block_given?
27
+
28
+ true
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :object, :fields
34
+ end
@@ -1,5 +1,8 @@
1
- module Ciesta
2
- module Types
3
- include Dry::Types.module
4
- end
1
+ # frozen_string_literal: true
2
+
3
+ # Module for type definitions
4
+ #
5
+ # @see http://dry-rb.org/gems/dry-validation/
6
+ module Ciesta::Types
7
+ include Dry::Types.module
5
8
  end
@@ -1,20 +1,38 @@
1
- module Ciesta
2
- class Validator
3
- attr_accessor :schema, :errors
1
+ # frozen_string_literal: true
4
2
 
5
- def initialize
6
- self.errors = []
7
- end
3
+ # Validatior class for form
4
+ #
5
+ # @api private
6
+ # @attr_reader [Dry::Validation::Schema] schema Schema for validation
7
+ # @attr_reader [Hash] errors Array with errors
8
+ class Ciesta::Validator
9
+ attr_reader :errors
8
10
 
9
- def use(&block)
10
- self.schema = Dry::Validation.Form(&block)
11
- end
11
+ # Constructor
12
+ def initialize
13
+ @errors = []
14
+ end
15
+
16
+ # Set schema for validation
17
+ #
18
+ # @param [Block] block Block wich returns the schema
19
+ def use(&block)
20
+ @schema = Dry::Validation.Form(&block)
21
+ end
12
22
 
13
- def valid?(attributes)
14
- return true if schema.nil?
23
+ # Checks if schema is valid
24
+ #
25
+ # @param [Hash<Symbol, any>] attributes Attributes to check
26
+ #
27
+ # @return [Boolean]
28
+ def valid?(attributes)
29
+ return true if schema.nil?
15
30
 
16
- self.errors = schema.call(attributes).errors
17
- errors.empty?
18
- end
31
+ @errors = schema.call(attributes).errors
32
+ errors.empty?
19
33
  end
34
+
35
+ private
36
+
37
+ attr_reader :schema
20
38
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ciesta
2
- VERSION = '0.1.1'.freeze
4
+ VERSION = "0.2.0".freeze
3
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ciesta
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexey
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-28 00:00:00.000000000 Z
11
+ date: 2018-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-types
@@ -116,7 +116,9 @@ extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
118
  - ".gitignore"
119
+ - ".hound.yml"
119
120
  - ".rspec"
121
+ - ".rubocop.yml"
120
122
  - ".travis.yml"
121
123
  - CODE_OF_CONDUCT.md
122
124
  - Gemfile
@@ -128,9 +130,12 @@ files:
128
130
  - bin/setup
129
131
  - ciesta.gemspec
130
132
  - lib/ciesta.rb
133
+ - lib/ciesta/delegator.rb
131
134
  - lib/ciesta/errors.rb
132
135
  - lib/ciesta/field.rb
136
+ - lib/ciesta/field_list.rb
133
137
  - lib/ciesta/form.rb
138
+ - lib/ciesta/syncer.rb
134
139
  - lib/ciesta/types.rb
135
140
  - lib/ciesta/validator.rb
136
141
  - lib/ciesta/version.rb