attributary 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/Gemfile +6 -0
- data/README.md +127 -0
- data/Rakefile +2 -0
- data/attributary.gemspec +24 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/.DS_Store +0 -0
- data/lib/attributary.rb +9 -0
- data/lib/attributary/.DS_Store +0 -0
- data/lib/attributary/config.rb +27 -0
- data/lib/attributary/core_ext.rb +15 -0
- data/lib/attributary/dsl.rb +87 -0
- data/lib/attributary/initializer.rb +13 -0
- data/lib/attributary/type.rb +18 -0
- data/lib/attributary/types/array_type.rb +9 -0
- data/lib/attributary/types/big_decimal_type.rb +9 -0
- data/lib/attributary/types/boolean_type.rb +13 -0
- data/lib/attributary/types/float_type.rb +9 -0
- data/lib/attributary/types/hash_type.rb +9 -0
- data/lib/attributary/types/integer_type.rb +9 -0
- data/lib/attributary/types/string_type.rb +9 -0
- data/lib/attributary/types/symbol_type.rb +9 -0
- data/lib/attributary/version.rb +3 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3ebdff0c364b0480e2c79d90df50064f2b015400
|
4
|
+
data.tar.gz: cef7eccd653b8c77ea68aa3f08a40ab89787ab63
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0aa7ee051f7a870076ff468b1f6b1a9b4ab91a1342e2e3c5f876c3fb7a024affd4b8a3b279cc933a2a340161444082f9702025a4d6b4e725d3682f747a707e51
|
7
|
+
data.tar.gz: d13c1daefa1c490e0a9fe70ac1dfbb626c477525716013bf1467212688b7c1f72b17821b857fa7679b5c05a730db844da493fa8923464e5556181199ee56a3b3
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
# Attributary
|
2
|
+
|
3
|
+
Like `ActiveModel::Attributes` but not. No dependencies.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'attributary'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install attributary
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
### Configuration
|
24
|
+
|
25
|
+
Attributary.configure do |c|
|
26
|
+
c.dsl_name = :donkey # defaults to :attrubute
|
27
|
+
c.strict_mode = false # set this to `true` to skip casting in the writer method (raises TypeError)
|
28
|
+
end
|
29
|
+
|
30
|
+
### Actually using it
|
31
|
+
|
32
|
+
class Character
|
33
|
+
include Attributary::DSL
|
34
|
+
|
35
|
+
donkey :gender, :symbol, default: :male
|
36
|
+
end
|
37
|
+
|
38
|
+
character = Character.new
|
39
|
+
puts character.gender # :male
|
40
|
+
character.gender = 'female'
|
41
|
+
puts character.gender # :female
|
42
|
+
|
43
|
+
### Initializing
|
44
|
+
|
45
|
+
Want to initialize? Cool.
|
46
|
+
|
47
|
+
class Character
|
48
|
+
include Attributary::Initializer
|
49
|
+
include Attributary::DSL
|
50
|
+
|
51
|
+
donkey :gender, :symbol, default: :male
|
52
|
+
end
|
53
|
+
|
54
|
+
character = Character.new(gender: :male)
|
55
|
+
puts character.gender # :male
|
56
|
+
|
57
|
+
Have to initialize other stuff? Send a hash to attributary_initialize
|
58
|
+
|
59
|
+
class Character
|
60
|
+
include Attributary::Initializer
|
61
|
+
include Attributary::DSL
|
62
|
+
|
63
|
+
donkey :gender, :symbol, default: :male
|
64
|
+
|
65
|
+
def initialize(name, attributary_attributes = {})
|
66
|
+
@name = name
|
67
|
+
attributary_initialize(attributary_attributes)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
character = Character.new("Charlie", gender: :male)
|
72
|
+
puts character.gender # :male
|
73
|
+
|
74
|
+
### Validations
|
75
|
+
|
76
|
+
There are two types of validations. You can pass a `:collection` option, and/or you can pass a `:validates` option.
|
77
|
+
|
78
|
+
#### Using `:collection`
|
79
|
+
|
80
|
+
Simply pass an array of the possible options for the attribute.
|
81
|
+
|
82
|
+
class Character
|
83
|
+
include Attributary::DSL
|
84
|
+
|
85
|
+
donkey :gender, :symbol, default: :male, collection: [:male, :female]
|
86
|
+
end
|
87
|
+
|
88
|
+
character = Character.new("Charlie", gender: :male)
|
89
|
+
puts character.gender # :male
|
90
|
+
character.gender = :left # raises CollectionValidationError
|
91
|
+
character.gender = :female
|
92
|
+
puts character.gender # :female
|
93
|
+
character.gender = 'male' # gets casted correctly, and doesn't raise an error. Turn this off with strict_mode
|
94
|
+
|
95
|
+
#### Using `:validates`
|
96
|
+
|
97
|
+
Pass a proc or a method name.
|
98
|
+
|
99
|
+
class Character
|
100
|
+
include Attributary::DSL
|
101
|
+
|
102
|
+
donkey :gender, :symbol, default: :male, validates: proc { |value| [:male, :female].include?(value) }
|
103
|
+
end
|
104
|
+
|
105
|
+
character = Character.new("Charlie", gender: :male)
|
106
|
+
puts character.gender # :male
|
107
|
+
character.gender = :left # raises CollectionValidationError
|
108
|
+
character.gender = 'female' # gets casted correctly, and doesn't raise an error
|
109
|
+
|
110
|
+
|
111
|
+
### Types
|
112
|
+
|
113
|
+
Supports some really naive typecasting. [See the supported types](https://github.com/joshmn/attributary/tree/master/lib/attributary/types). Create your own by inheriting from `Attributary::Types` and naming it like `ClassNameType`
|
114
|
+
|
115
|
+
module Attributary
|
116
|
+
module Types
|
117
|
+
class FriendType < Type
|
118
|
+
def self.cast_to(value)
|
119
|
+
Foe.new(value)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
## Contributing
|
126
|
+
|
127
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/joshmn/attributary
|
data/Rakefile
ADDED
data/attributary.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'attributary/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'attributary'
|
7
|
+
spec.version = Attributary::VERSION
|
8
|
+
spec.authors = ['Josh Brody']
|
9
|
+
spec.email = ['josh@josh.mn']
|
10
|
+
|
11
|
+
spec.summary = 'Like ActiveModel::Attributes but less fluffy and more attribute-y.'
|
12
|
+
spec.description = 'Like `ActiveModel::Attributes` but less fluffy and more attribute-y.'
|
13
|
+
spec.homepage = 'https://github.com/joshmn/attributary'
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
16
|
+
f.match(%r{^(test|spec|features)/})
|
17
|
+
end
|
18
|
+
spec.bindir = 'exe'
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.15'
|
23
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
24
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'attributary'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require 'irb'
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/.DS_Store
ADDED
Binary file
|
data/lib/attributary.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require_relative 'attributary/config'
|
2
|
+
require_relative 'attributary/core_ext'
|
3
|
+
require_relative 'attributary/type'
|
4
|
+
require_relative 'attributary/initializer'
|
5
|
+
require_relative 'attributary/dsl'
|
6
|
+
require_relative 'attributary/version'
|
7
|
+
|
8
|
+
module Attributary
|
9
|
+
end
|
Binary file
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Attributary
|
2
|
+
def self.configuration
|
3
|
+
@configuration || Config.new
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.configuration=(val)
|
7
|
+
@configuration = val
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.configure
|
11
|
+
self.configuration ||= Config.new
|
12
|
+
yield(configuration)
|
13
|
+
end
|
14
|
+
|
15
|
+
class Config
|
16
|
+
attr_accessor :dsl_name, :strict_mode
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@dsl_name = :attribute
|
20
|
+
@strict_mode = false
|
21
|
+
end
|
22
|
+
|
23
|
+
def strict_mode?
|
24
|
+
@strict_mode
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Attributary
|
2
|
+
module DSL
|
3
|
+
class ValidationError < StandardError; end
|
4
|
+
class CollectionValidationError < StandardError; end
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def _attributary_attribute_set
|
12
|
+
@_attributary_attribute_set ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def _attributary_attributes
|
16
|
+
hash = {}
|
17
|
+
_attributary_attribute_set.keys.each do |k|
|
18
|
+
hash[k] = instance_variable_get(:"@#{k}")
|
19
|
+
end
|
20
|
+
hash
|
21
|
+
end
|
22
|
+
|
23
|
+
define_method(Attributary.configuration.dsl_name) do |name, type, options = {}|
|
24
|
+
options[:type] = type
|
25
|
+
_attributary_attribute_set[name] = options
|
26
|
+
_attributary_reader(name, type, options)
|
27
|
+
_attributary_writer(name, type, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def _attributary_reader(name, type, options)
|
31
|
+
define_method(name) do
|
32
|
+
instance_variable_get(:"@#{name}") || if options[:default].is_a?(Proc)
|
33
|
+
options[:default].call
|
34
|
+
else
|
35
|
+
options[:default]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
if type == :boolean
|
39
|
+
define_method("#{name}?") do
|
40
|
+
send(name.to_s)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def _attributary_writer(name, type, options)
|
46
|
+
define_method("#{name}=") do |value|
|
47
|
+
value = self.class._attributary_cast_to(type, value) unless Attributary.configuration.strict_mode?
|
48
|
+
self.class._attributary_check_collection(value, options[:collection]) if options[:collection].is_a?(Array)
|
49
|
+
self.class._attributary_validate_attribute(value, options[:validates])
|
50
|
+
instance_variable_set(:"@#{name}", value)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def _attributary_check_collection(value, collection)
|
55
|
+
unless collection.include?(value)
|
56
|
+
raise CollectionValidationError, "Value `#{value}' is not in the collection #{collection}."
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def _attributary_validate_attribute(value, validator)
|
61
|
+
return true if validator.nil?
|
62
|
+
raise ValidationError, 'Validator failed.' unless validator.call(value)
|
63
|
+
end
|
64
|
+
|
65
|
+
def _attributary_cast_to(type, value)
|
66
|
+
cast_klass = _attributary_cast_class(type)
|
67
|
+
cast_klass.cast_to(value)
|
68
|
+
end
|
69
|
+
|
70
|
+
def _attributary_cast_class(type)
|
71
|
+
cast_klass_name = _attributary_cast_class_name(type)
|
72
|
+
cast_klass = cast_klass_name.safe_constantize
|
73
|
+
if cast_klass.nil?
|
74
|
+
raise NameError, "#{cast_klass_name} is not a valid type."
|
75
|
+
end
|
76
|
+
unless cast_klass.respond_to?(:cast_to)
|
77
|
+
raise NoMethodError, "#{cast_klass} should have a class-method of cast_to"
|
78
|
+
end
|
79
|
+
cast_klass
|
80
|
+
end
|
81
|
+
|
82
|
+
def _attributary_cast_class_name(type)
|
83
|
+
"Attributary::Types::#{type.to_s.split('_').map(&:capitalize).join}Type"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Attributary
|
2
|
+
module Types
|
3
|
+
class Type
|
4
|
+
def self.cast_to(value)
|
5
|
+
value
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require_relative 'types/array_type'
|
12
|
+
require_relative 'types/big_decimal_type'
|
13
|
+
require_relative 'types/boolean_type'
|
14
|
+
require_relative 'types/float_type'
|
15
|
+
require_relative 'types/hash_type'
|
16
|
+
require_relative 'types/integer_type'
|
17
|
+
require_relative 'types/string_type'
|
18
|
+
require_relative 'types/symbol_type'
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: attributary
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Josh Brody
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-06-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.15'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: Like `ActiveModel::Attributes` but less fluffy and more attribute-y.
|
42
|
+
email:
|
43
|
+
- josh@josh.mn
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".gitignore"
|
49
|
+
- Gemfile
|
50
|
+
- README.md
|
51
|
+
- Rakefile
|
52
|
+
- attributary.gemspec
|
53
|
+
- bin/console
|
54
|
+
- bin/setup
|
55
|
+
- lib/.DS_Store
|
56
|
+
- lib/attributary.rb
|
57
|
+
- lib/attributary/.DS_Store
|
58
|
+
- lib/attributary/config.rb
|
59
|
+
- lib/attributary/core_ext.rb
|
60
|
+
- lib/attributary/dsl.rb
|
61
|
+
- lib/attributary/initializer.rb
|
62
|
+
- lib/attributary/type.rb
|
63
|
+
- lib/attributary/types/array_type.rb
|
64
|
+
- lib/attributary/types/big_decimal_type.rb
|
65
|
+
- lib/attributary/types/boolean_type.rb
|
66
|
+
- lib/attributary/types/float_type.rb
|
67
|
+
- lib/attributary/types/hash_type.rb
|
68
|
+
- lib/attributary/types/integer_type.rb
|
69
|
+
- lib/attributary/types/string_type.rb
|
70
|
+
- lib/attributary/types/symbol_type.rb
|
71
|
+
- lib/attributary/version.rb
|
72
|
+
homepage: https://github.com/joshmn/attributary
|
73
|
+
licenses: []
|
74
|
+
metadata: {}
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.6.13
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: Like ActiveModel::Attributes but less fluffy and more attribute-y.
|
95
|
+
test_files: []
|