ciesta 0.3.2 → 0.4.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: 2c546a423a524c000586945f454df552aad095cc9cf83c9f5a5a1f632c270a44
4
- data.tar.gz: 2a8699af62652d17dc4f0705136855e827a1273488c873022c3057621058abfe
3
+ metadata.gz: 5edecb23ff1a41bdee5b20058e2a3f89688cb84c4c75d5bca1dd588388cfccbf
4
+ data.tar.gz: 2e31ce2197aee8f2289026a1589c838c31eeb589d0f223ccb55a4801b19eaea1
5
5
  SHA512:
6
- metadata.gz: 45f65ccdfbc46528f966fe48ccb799c1232bf67e00db3572569788b3560cd8b59c7d0154578c76bd71d234e38498025e13187af6d0a89ba8a7a236e794f72ef7
7
- data.tar.gz: f8274e3f6e55fb7774634ea3ac47ed84514f3bcc50093220559192e4e52458bf7398e245824d0519577010ad393f2f10fa23eb4e40d18e770eb08003eae8141b
6
+ metadata.gz: cf6686bed0df0f9cc26e5c0f7447e636603e6ceb0802fe7f36e40906850b702bab4514265e5e5f642ae712ee375d8336788af1fd4413b9379d822ee275001f4d
7
+ data.tar.gz: e33e92164712e7720c6842b52d7064bfe232608b78ed44bb50e29674e64261260ab9aa0d5ef009593db38096430b0c2a2cd8e0b77dd5dd958699fbc4bf964258
@@ -34,5 +34,8 @@ Style/ModuleFunction:
34
34
  Lint/AmbiguousOperator:
35
35
  Enabled: false
36
36
 
37
+ Layout/IndentArray:
38
+ EnforcedStyle: consistent
39
+
37
40
  Lint/AmbiguousBlockAssociation:
38
41
  Enabled: false
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ciesta (0.3.2)
4
+ ciesta (0.4.0)
5
5
  dry-types (~> 0.13)
6
6
  dry-validation (~> 0.12)
7
7
 
@@ -102,6 +102,7 @@ DEPENDENCIES
102
102
  rake (~> 10.5)
103
103
  rspec (~> 3.8)
104
104
  rubocop (~> 0.59)
105
+ simplecov (~> 0.16)
105
106
 
106
107
  BUNDLED WITH
107
108
  1.16.3
data/README.md CHANGED
@@ -10,18 +10,17 @@ Supported Ruby 2.2.0+
10
10
 
11
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
12
 
13
- - [Installation](#installation)
14
- - [Usage](#usage)
15
- - [Basic case](#basic-case)
16
- - [Syncing](#syncing)
17
- - [Validation](#validation)
18
- - [Advanced field declaration](#advanced-field-declaration)
19
- - [Types](#types)
20
- - [Default value](#default-value)
21
- - [Virtual field](#virtual-field)
13
+ - [Ciesta](#ciesta)
14
+ - [Installation](#installation)
15
+ - [Usage](#usage)
16
+ - [Basic case](#basic-case)
17
+ - [Validation](#validation)
18
+ - [Advanced field declaration](#advanced-field-declaration)
19
+ - [Types](#types)
20
+ - [Default value](#default-value)
22
21
  - [Values mass update](#values-mass-update)
23
- - [Contributing](#contributing)
24
- - [License](#license)
22
+ - [Contributing](#contributing)
23
+ - [License](#license)
25
24
 
26
25
  ## Installation
27
26
 
@@ -43,12 +42,10 @@ Or install it yourself as:
43
42
  ## Usage
44
43
 
45
44
  ### Basic case
46
- For example will be used user object with `name` and `age` attributes:
45
+ For example will be used a hash with `name` and `age` attributes:
47
46
 
48
47
  ```ruby
49
- User = Struct.new(:name, :age)
50
-
51
- user = User.new(nil, nil)
48
+ user = Hash[name: nil, age: nil]
52
49
  ```
53
50
 
54
51
  For setting and syncing new values let's create a form object:
@@ -71,22 +68,8 @@ form = Form.new(user)
71
68
  ```ruby
72
69
  form.name = "John"
73
70
  form.age = "33"
74
- form.sync!
75
-
76
- user.name # => "John"
77
- user.age # => 33
78
71
  ```
79
72
 
80
- ### Syncing
81
- You can pass a block to sync method to do some stuff with object after syncing.
82
-
83
- ```ruby
84
- form.sync! do |user|
85
- user.make_happy!
86
- end
87
- ```
88
- Both `sync` and `sync!` provide this DSL.
89
-
90
73
  ### Validation
91
74
  For validating incoming values you can use `validate` method:
92
75
 
@@ -111,13 +94,10 @@ An attempt to sync with invalid form will raise `Ciesta::FormNotValid` error.
111
94
  ```ruby
112
95
  form.age = 15
113
96
  form.valid? # => false
114
- form.sync! # => raises Ciesta::FormNotValid
115
97
  form.errors # => { age: ["must be greater than 18"] }
116
98
  ...
117
99
  form.age = 42
118
- form.sync! # => true
119
-
120
- user.age # => 42
100
+ form.valid? # => true
121
101
  ```
122
102
 
123
103
  ### Advanced field declaration
@@ -159,25 +139,11 @@ field :age, default: -> { default_age }
159
139
  form.age # => 42
160
140
  ```
161
141
 
162
- ### Virtual field
163
- You can declare field as "virtual". It means that when you call `sync!` it will not raise an error "model attribute is not defined".
164
-
165
- ```ruby
166
- User = Struct.new(:name)
167
- ...
168
- field :age, virtual: true
169
- ...
170
- form.age = "42"
171
- form.age # => 42
172
- form.sync! # => true
173
- ```
174
-
175
142
  ## Values mass update
176
143
  There are two methods for form fields mass update: `assign` and `assign!`.
177
144
 
178
145
  ```ruby
179
146
  form.assign!(name: "Neo", age: 30)
180
- form.sync!
181
147
  ...
182
148
  user.name # => "Neo"
183
149
  user.age # => 30
@@ -185,6 +151,7 @@ user.age # => 30
185
151
 
186
152
  `assign!` method will raise `Ciesta::FieldNotDefined` error if one of the passed attributes is not declared in the form.
187
153
 
154
+
188
155
  ## Contributing
189
156
 
190
157
  Bug reports and pull requests are welcome on GitHub at [https://github.com/nulldef/ciesta](https://github.com/nulldef/ciesta).
@@ -38,4 +38,5 @@ Gem::Specification.new do |spec|
38
38
  spec.add_development_dependency "rake", "~> 10.5"
39
39
  spec.add_development_dependency "rspec", "~> 3.8"
40
40
  spec.add_development_dependency "rubocop", "~> 0.59"
41
+ spec.add_development_dependency "simplecov", "~> 0.16"
41
42
  end
@@ -5,7 +5,6 @@ require "dry-types"
5
5
  require "dry-validation"
6
6
  require "ciesta/version"
7
7
  require "ciesta/field_list"
8
- require "ciesta/syncer"
9
8
  require "ciesta/types"
10
9
  require "ciesta/validator"
11
10
  require "ciesta/errors"
@@ -2,14 +2,6 @@ module Ciesta
2
2
  module ClassMethods
3
3
  extend self
4
4
 
5
- def form_from(**hash)
6
- form = new
7
- hash.each do |(k, v)|
8
- form.public_send("#{k}=", v) if form.respond_to?("#{k}=")
9
- end
10
- form
11
- end
12
-
13
5
  # Declare new form field
14
6
  #
15
7
  # @param [Symbol] name Field name
@@ -17,14 +9,14 @@ module Ciesta
17
9
  # @option (see Ciesta::Field)
18
10
  def field(name, **options)
19
11
  name = name.to_sym
20
- fields << Ciesta::Field.new(name, options)
12
+ definitions[name] = options
21
13
  proxy.instance_eval do
22
- define_method(name) { self.class.fields[name] }
23
- define_method("#{name}=") { |value| self.class.fields[name] = value }
14
+ define_method(name) { fields[name] }
15
+ define_method("#{name}=") { |value| fields[name] = value }
24
16
  end
25
17
  end
26
18
 
27
- # Declare rules for valudation
19
+ # Declare rules for validation
28
20
  #
29
21
  # @param [Block] block Block with validation rules
30
22
  # @see http://dry-rb.org/gems/dry-validation
@@ -32,12 +24,12 @@ module Ciesta
32
24
  validator.use(&block)
33
25
  end
34
26
 
35
- # Returns field list
27
+ # Returns fields definitions
36
28
  #
37
29
  # @api private
38
30
  # @return [Ciesta::FieldList]
39
- def fields
40
- @fields ||= Ciesta::FieldList.new
31
+ def definitions
32
+ @definitions ||= {}
41
33
  end
42
34
 
43
35
  # Returns form validator
@@ -4,15 +4,6 @@ module Ciesta
4
4
  # Error for violating constraints
5
5
  ViolatesConstraints = Class.new(ArgumentError)
6
6
 
7
- # Error for invalid object
8
- FormNotValid = Class.new(StandardError)
9
-
10
7
  # Error for missing field definition
11
8
  FieldNotDefined = Class.new(NoMethodError)
12
-
13
- # Error for missing method of model
14
- AttributeNotDefined = Class.new(NoMethodError)
15
-
16
- # Error for nil object
17
- ModelNotPresent = Class.new(StandardError)
18
9
  end
@@ -16,11 +16,10 @@ class Ciesta::Field
16
16
  # @param [Hash] options Field's options
17
17
  # @option [Ciesta::Types::Definition] :type Type of value stored in this field
18
18
  # @option [Proc, Lambda, any] :default Default value for this field
19
- def initialize(name, options)
19
+ def initialize(name, **options)
20
20
  @name = name.to_sym
21
21
  @type = options.delete(:type) || DEFAULT_TYPE
22
22
  @default = options.delete(:default)
23
- @virtual = options.delete(:virtual) || false
24
23
  end
25
24
 
26
25
  # Sets a new value for field
@@ -32,7 +31,7 @@ class Ciesta::Field
32
31
  @value = type[val]
33
32
  @was_set = true
34
33
  rescue Dry::Types::ConstraintError
35
- raise Ciesta::ViolatesConstraints, "#{val} is not a #{type.name}"
34
+ raise Ciesta::ViolatesConstraints, "#{val} is not a valid #{name} (#{type.name})"
36
35
  end
37
36
 
38
37
  # Returns current value
@@ -52,15 +51,6 @@ class Ciesta::Field
52
51
  @binding = obj
53
52
  end
54
53
 
55
- # Returns true if field is virtual
56
- #
57
- # @api private
58
- #
59
- # @return [Boolean]
60
- def virtual?
61
- @virtual
62
- end
63
-
64
54
  # Clear field
65
55
  def clear!
66
56
  @value = nil
@@ -4,6 +4,18 @@
4
4
  #
5
5
  # @attr_reader [Hash<Symbol, Ciesta::Field>] list Field list
6
6
  class Ciesta::FieldList
7
+ # Define a new field list
8
+ #
9
+ # @api private
10
+ # @param [Hash] definitions Hash of fields definitions
11
+ #
12
+ # @return Ciesta::FieldList
13
+ def self.define(definitions)
14
+ definitions.each_with_object(new) do |(name, options), list|
15
+ list << Ciesta::Field.new(name, options)
16
+ end
17
+ end
18
+
7
19
  # Constructor
8
20
  def initialize
9
21
  @list = {}
@@ -44,7 +56,6 @@ class Ciesta::FieldList
44
56
  # @return [Boolean]
45
57
  def assign!(attributes)
46
58
  attributes.each { |name, value| self[name] = value }
47
- true
48
59
  rescue NoMethodError => e
49
60
  raise Ciesta::FieldNotDefined, "Field #{e.name} is not specified"
50
61
  end
@@ -58,8 +69,8 @@ class Ciesta::FieldList
58
69
  attributes = attributes.keep_if { |key| keys.include?(key) }
59
70
  begin
60
71
  assign!(attributes)
61
- rescue StandardError
62
- false
72
+ rescue Ciesta::FieldNotDefined # rubocop:disable Lint/HandleExceptions
73
+ # do nothing
63
74
  end
64
75
  end
65
76
 
@@ -79,14 +90,6 @@ class Ciesta::FieldList
79
90
  list.values.map { |field| [field.name, field.value] }.to_h
80
91
  end
81
92
 
82
- # Iterate over all fields
83
- #
84
- # @api private
85
- # @param [Block] block Block to iterate
86
- def each
87
- list.each_value { |field| yield(field) }
88
- end
89
-
90
93
  # Clear all fields
91
94
  #
92
95
  # @api private
@@ -12,27 +12,14 @@ module Ciesta
12
12
  # @see Ciesta::Validator
13
13
  def_delegators :validator, :errors
14
14
 
15
- # @!method sync
16
- # @!method sync!
17
- # @see Ciesta::Syncer
18
- def_delegators :syncer, :sync
19
-
20
- attr_accessor :object
15
+ attr_reader :fields
21
16
 
22
17
  # Constructor
23
18
  #
24
- # @param [Object] object Object wich will be updated though this form
25
- def initialize(object = nil)
26
- @object = object
27
- clear!
28
-
29
- return if object.nil?
30
-
31
- values = fields.keys.each_with_object({}) do |key, mem|
32
- mem[key] = object.public_send(key) if object.respond_to?(key)
33
- end
34
-
35
- assign(values)
19
+ # @param [Hash] values Hash with values
20
+ def initialize(values = {})
21
+ @fields = Ciesta::FieldList.define(self.class.definitions)
22
+ assign(values || {})
36
23
  end
37
24
 
38
25
  # Checks if form is valid
@@ -40,36 +27,13 @@ module Ciesta
40
27
  # @param [Hash] params Attrubutes to assign before validation
41
28
  #
42
29
  # @return [Boolean]
43
- def valid?(params = nil)
44
- assign(params) if params
30
+ def valid?(values = {})
31
+ assign(values) unless values.empty?
45
32
  validator.valid?(attributes)
46
33
  end
47
34
 
48
- # Sync form attributes to object
49
- #
50
- # @see Ciesta::Syncer
51
- #
52
- # @param [Block] block Block wich will be yielded after synfing
53
- #
54
- # @raise Ciesta::ModelNotPresent
55
- # @raise Ciesta::FormNotValid
56
- # @return [Boolean]
57
- def sync!(&block)
58
- raise Ciesta::FormNotValid, "Form is not valid" unless valid?
59
-
60
- syncer.sync!(&block)
61
- end
62
-
63
35
  private
64
36
 
65
- # Sync class for form
66
- #
67
- # @api private
68
- # @return [Ciesta::Syncer]
69
- def syncer
70
- @syncer ||= Ciesta::Syncer.new(object, fields)
71
- end
72
-
73
37
  # Returns form validator
74
38
  #
75
39
  # @api private
@@ -77,13 +41,5 @@ module Ciesta
77
41
  def validator
78
42
  self.class.validator
79
43
  end
80
-
81
- # Returns field list
82
- #
83
- # @api private
84
- # @see Ciesta::Form.fields
85
- def fields
86
- self.class.fields
87
- end
88
44
  end
89
45
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ciesta
4
- VERSION = "0.3.2".freeze
4
+ VERSION = "0.4.0".freeze
5
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.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-11 00:00:00.000000000 Z
11
+ date: 2018-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-types
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0.59'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.16'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.16'
125
139
  description: Gem for creating and using form object
126
140
  email:
127
141
  - nulldefiner@gmail.com
@@ -151,7 +165,6 @@ files:
151
165
  - lib/ciesta/field.rb
152
166
  - lib/ciesta/field_list.rb
153
167
  - lib/ciesta/instance_methods.rb
154
- - lib/ciesta/syncer.rb
155
168
  - lib/ciesta/types.rb
156
169
  - lib/ciesta/validator.rb
157
170
  - lib/ciesta/version.rb
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Class for syncing fields and object
4
- #
5
- # @attr_reader [Object] object Form objecy
6
- # @attr_reader [Ciesta::FieldList] fields Field list
7
- class Ciesta::Syncer
8
- # Constructor
9
- #
10
- # @api private
11
- # @param [Object] object Form object
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 object
19
- #
20
- # @param [Block] block Block which will be yielded after syncing
21
- #
22
- # @return [Booelan]
23
- def sync
24
- return if object.nil?
25
-
26
- fields.each do |field|
27
- begin
28
- save_to_object(field)
29
- rescue StandardError
30
- nil
31
- end
32
- end
33
-
34
- yield(object) if block_given?
35
-
36
- true
37
- end
38
-
39
- # Sync attributes with object
40
- #
41
- # @param [Block] block Block which will be yielded after syncing
42
- #
43
- # @raise Ciesta::ModelNotPresent
44
- # @raise Ciesta::AttributeNotDefined
45
- # @return [Booelan]
46
- def sync!
47
- raise Ciesta::ModelNotPresent, "Cannot sync without model" if object.nil?
48
-
49
- fields.each { |field| save_to_object(field) }
50
-
51
- yield(object) if block_given?
52
-
53
- true
54
- end
55
-
56
- private
57
-
58
- attr_reader :object, :fields
59
-
60
- def save_to_object(field)
61
- object.send("#{field.name}=", field.value) unless field.virtual?
62
- rescue NoMethodError
63
- raise Ciesta::AttributeNotDefined, "Attribute #{field.name} is not defined on model"
64
- end
65
- end