pure_form 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7025ebff1558b57eb3dc586e5f6fcbb4af7c6680
4
+ data.tar.gz: 9a923ef9e28728fd0ce013a7c2d7f7aba6466cec
5
+ SHA512:
6
+ metadata.gz: 9094f32da6ee09629c3da92d650ba85351b65f8ad949993d41aeeb1d4a9fc68b8c0da8b8efd6a97c63b6dc86c6f3044f3877b31af94bb0c12462982dda8f970e
7
+ data.tar.gz: c7800172e42789f6d37a445a58c9df83acadaf8f0dd05ab2353e9d01062217cf37d13970f8d47b1b93803b484362976a0ccd8b59c78d1b0a00533ca4e169dac4
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Pavel Pravosud
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
+ # PureForm
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 'pure_form'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install pure_form
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/pure_form/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/lib/pure_form.rb ADDED
@@ -0,0 +1,10 @@
1
+ require "active_support/all"
2
+
3
+ module PureForm
4
+ autoload :VERSION, "pure_form/version"
5
+ autoload :Attribute, "pure_form/attribute"
6
+ autoload :Assignment, "pure_form/assignment"
7
+ autoload :Types, "pure_form/types"
8
+ autoload :Base, "pure_form/base"
9
+ autoload :Errors, "pure_form/errors"
10
+ end
@@ -0,0 +1,49 @@
1
+ module PureForm
2
+ class Assignment
3
+ attr_reader :form, :attributes
4
+
5
+ def initialize(form, attributes)
6
+ @form, @attributes = form, attributes
7
+ end
8
+
9
+ def perform
10
+ attributes.each do |key, value|
11
+ if key =~ /\(\d+[if]\)\z/
12
+ assign_complex_attribute key, value
13
+ else
14
+ assign_attribute key, value
15
+ end
16
+ end
17
+
18
+ flush_complex_attributes
19
+ end
20
+
21
+ private
22
+
23
+ def assign_attribute(attribute_name, value)
24
+ setter = "#{attribute_name}="
25
+ fail Errors::UnknownAttributeError.build(attribute_name) unless form.respond_to?(setter)
26
+ form.public_send setter, value
27
+ end
28
+
29
+ def assign_complex_attribute(complex_attribute_name, value)
30
+ attribute_name = complex_attribute_name[/\A[^(]+/]
31
+ attribute_position = complex_attribute_name[/\((\d+)[if]\)\z/, 1].to_i - 1
32
+ attribute_type = complex_attribute_name[/([if])\)\z/, 1]
33
+ value = value.public_send("to_#{attribute_type}")
34
+ complex_attributes[attribute_name][attribute_position] = value
35
+ end
36
+
37
+ def complex_attributes
38
+ @complex_attributes ||= Hash.new{ |hash, key| hash[key] = [] }
39
+ end
40
+
41
+ def flush_complex_attributes
42
+ complex_attributes.each do |key, values|
43
+ method_name = "set_complex_#{key}_value"
44
+ raise Errors::MissingComplexAttributeError.build(key) unless form.respond_to?(method_name)
45
+ form.public_send method_name, *values
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,71 @@
1
+ module PureForm
2
+ class Attribute
3
+ attr_reader :context, :name, :options, :value_type
4
+
5
+ def initialize(context, name, options)
6
+ @context, @name, @options = context, name.to_s, options
7
+ @value_type = build_value_type
8
+ end
9
+
10
+ def define
11
+ define_setter
12
+ define_complex_setter
13
+ define_getter
14
+ define_predicate
15
+ end
16
+
17
+ private
18
+
19
+ def define_setter
20
+ define_for_context "#{name}=", &setter_proc
21
+ end
22
+
23
+ def define_complex_setter
24
+ return unless value_type.respond_to?(:complex_typecast)
25
+ method_name = "set_complex_#{name}_value"
26
+ define_for_context method_name, &complex_setter_proc
27
+ end
28
+
29
+ def define_getter
30
+ define_for_context name, &getter_proc
31
+ end
32
+
33
+ def define_predicate
34
+ define_for_context "#{name}?", &predicate_proc
35
+ end
36
+
37
+ def define_for_context(name, &block)
38
+ context.instance_eval do
39
+ define_method name, &block
40
+ end
41
+ end
42
+
43
+ def setter_proc
44
+ attribute_name = self.name
45
+ type = value_type
46
+ ->(value){ store_attribute(attribute_name, type.typecast(value)) }
47
+ end
48
+
49
+ def complex_setter_proc
50
+ setter_name = "#{name}="
51
+ type = value_type
52
+ ->(*values){ public_send setter_name, type.complex_typecast(*values) }
53
+ end
54
+
55
+ def getter_proc
56
+ attribute_name = self.name
57
+ ->{ read_attribute(attribute_name) }
58
+ end
59
+
60
+ def predicate_proc
61
+ attribute_name = self.name
62
+ ->{ public_send(attribute_name).present? }
63
+ end
64
+
65
+ def build_value_type
66
+ return Types::BaseType.new(options) unless options.key?(:type)
67
+ type = options.delete(:type)
68
+ "PureForm::Types::#{type.to_s.classify}Type".constantize.new(options)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,85 @@
1
+ require "active_model"
2
+
3
+ module PureForm
4
+ class Base
5
+ include ActiveModel::Model
6
+
7
+ class_attribute :attributes, instance_accessor: false, instance_predicate: false
8
+
9
+ class << self
10
+ def attribute(name, **options)
11
+ attribute = Attribute.new(self, name, options)
12
+ self.attributes ||= HashWithIndifferentAccess.new
13
+ self.attributes = attributes.merge(name => attribute)
14
+ attribute.define
15
+ end
16
+
17
+ def model_name
18
+ @model_name ||= build_model_name(to_s.remove(/^(\w+::)+/).remove(/Form$/))
19
+ end
20
+
21
+ def form_name(name)
22
+ new_name = build_model_name(name)
23
+ singleton_class.instance_eval do
24
+ define_method(:model_name){ new_name }
25
+ end
26
+ end
27
+
28
+ def default_values
29
+ return {} unless attributes
30
+ @default_values ||= attributes.each_with_object({}) do |(name, attribute), defaults|
31
+ if attribute.options.key?(:default)
32
+ defaults[name] = attribute.options.fetch(:default)
33
+ end
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def build_model_name(name)
40
+ ActiveModel::Name.new(self, nil, name.to_s)
41
+ end
42
+ end
43
+
44
+ def initialize(attributes=nil)
45
+ assign_defaults
46
+ assign_attributes attributes if attributes
47
+ end
48
+
49
+ def assign_attributes(attributes)
50
+ Assignment.new(self, attributes).perform
51
+ end
52
+
53
+ alias_method :attributes=, :assign_attributes
54
+
55
+ def attributes
56
+ self.class.attributes.each_with_object({}) do |(name, _), attributes|
57
+ attributes[name] = public_send(name)
58
+ end.with_indifferent_access
59
+ end
60
+
61
+ def update(updates)
62
+ assign_attributes updates
63
+ valid?
64
+ end
65
+
66
+ private
67
+
68
+ def assign_defaults
69
+ defaults = self.class.default_values
70
+ assign_attributes defaults unless defaults.empty?
71
+ end
72
+
73
+ def attributes_store
74
+ @attributes_store ||= Hash.new
75
+ end
76
+
77
+ def store_attribute(name, value)
78
+ attributes_store.store name, value
79
+ end
80
+
81
+ def read_attribute(name)
82
+ attributes_store[name]
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,6 @@
1
+ module PureForm
2
+ module Errors
3
+ autoload :UnknownAttributeError, "pure_form/errors/unknown_attribute"
4
+ autoload :MissingComplexAttributeError, "pure_form/errors/missing_complex_attribute"
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ module PureForm
2
+ module Errors
3
+ class MissingComplexAttributeError < StandardError
4
+ def self.build(key)
5
+ new(":#{key} attribute doesn't have a complex setter")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module PureForm
2
+ module Errors
3
+ class UnknownAttributeError < NoMethodError
4
+ def self.build(key)
5
+ new("No such attribute: #{key.inspect}")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ module PureForm
2
+ module Types
3
+ autoload :BaseType, "pure_form/types/base"
4
+ autoload :StringType, "pure_form/types/string"
5
+ autoload :IntegerType, "pure_form/types/integer"
6
+ autoload :FloatType, "pure_form/types/float"
7
+ autoload :BooleanType, "pure_form/types/boolean"
8
+ autoload :DateType, "pure_form/types/date"
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ module PureForm
2
+ module Types
3
+ class BaseType
4
+ def initialize(options={})
5
+ @options = options
6
+ end
7
+
8
+ def typecast(value)
9
+ value
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module PureForm
2
+ module Types
3
+ class BooleanType < BaseType
4
+ TRUE_VALUES = [true, 1, "1", "t", "T", "true", "TRUE", "on", "ON"].to_set
5
+
6
+ def typecast(value)
7
+ TRUE_VALUES.include?(value)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ module PureForm
2
+ module Types
3
+ class DateType < BaseType
4
+ def typecast(value)
5
+ value.to_date
6
+ rescue TypeError, ArgumentError, NoMethodError
7
+ nil
8
+ end
9
+
10
+ def complex_typecast(year, month, day)
11
+ Date.new(year, month, day)
12
+ rescue TypeError, ArgumentError
13
+ nil
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module PureForm
2
+ module Types
3
+ class FloatType < BaseType
4
+ def typecast(value)
5
+ value.to_f
6
+ rescue NoMethodError
7
+ nil
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module PureForm
2
+ module Types
3
+ class IntegerType < BaseType
4
+ def typecast(value)
5
+ value.to_i
6
+ rescue NoMethodError
7
+ nil
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module PureForm
2
+ module Types
3
+ class StringType < BaseType
4
+ def typecast(value)
5
+ value.to_s
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module PureForm
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pure_form
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Pavel Pravosud
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activemodel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ description:
28
+ email:
29
+ - pavel@pravosud.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - LICENSE.txt
35
+ - README.md
36
+ - lib/pure_form.rb
37
+ - lib/pure_form/assignment.rb
38
+ - lib/pure_form/attribute.rb
39
+ - lib/pure_form/base.rb
40
+ - lib/pure_form/errors.rb
41
+ - lib/pure_form/errors/missing_complex_attribute.rb
42
+ - lib/pure_form/errors/unknown_attribute.rb
43
+ - lib/pure_form/types.rb
44
+ - lib/pure_form/types/base.rb
45
+ - lib/pure_form/types/boolean.rb
46
+ - lib/pure_form/types/date.rb
47
+ - lib/pure_form/types/float.rb
48
+ - lib/pure_form/types/integer.rb
49
+ - lib/pure_form/types/string.rb
50
+ - lib/pure_form/version.rb
51
+ homepage: https://github.com/rwz/pure_form
52
+ licenses:
53
+ - MIT
54
+ metadata: {}
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '2.0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubyforge_project:
71
+ rubygems_version: 2.2.2
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: ''
75
+ test_files: []