ciesta 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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