attributary 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in attributary.gemspec
6
+ gemspec
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
@@ -0,0 +1,2 @@
1
+ require 'bundler/gem_tasks'
2
+ task default: :spec
@@ -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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/.DS_Store ADDED
Binary file
@@ -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,15 @@
1
+ class String
2
+ unless String.respond_to?(:constantize)
3
+ def constantize
4
+ Object.const_get(self)
5
+ end
6
+ end
7
+
8
+ unless String.respond_to?(:safe_constantize)
9
+ def safe_constantize
10
+ constantize
11
+ rescue StandardError
12
+ nil
13
+ end
14
+ end
15
+ 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,13 @@
1
+ module Attributary
2
+ module Initializer
3
+ def initialize(options = {})
4
+ attributary_initialize(options)
5
+ end
6
+
7
+ def attributary_initialize(options = {})
8
+ options.each do |k, v|
9
+ send("#{k}=", v) if attribute_set[k]
10
+ end
11
+ end
12
+ end
13
+ 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'
@@ -0,0 +1,9 @@
1
+ module Attributary
2
+ module Types
3
+ class ArrayType < Type
4
+ def self.cast_to(value)
5
+ value.to_a
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Attributary
2
+ module Types
3
+ class BigDecimal < Type
4
+ def self.cast_to(value)
5
+ BigDecimal(value.to_s)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module Attributary
2
+ module Types
3
+ class BooleanType < Type
4
+ def self.cast_to(value)
5
+ if ['false', 0, '0', false, nil, ''].include?(value)
6
+ false
7
+ else
8
+ true
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module Attributary
2
+ module Types
3
+ class FloatType < Type
4
+ def self.cast_to(value)
5
+ value.to_f
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Attributary
2
+ module Types
3
+ class HashType < Type
4
+ def self.cast_to(value)
5
+ value.is_a?(Hash) ? value : value.to_h
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Attributary
2
+ module Types
3
+ class IntegerType < Type
4
+ def self.cast_to(value)
5
+ value.to_i
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Attributary
2
+ module Types
3
+ class StringType < Type
4
+ def self.cast_to(value)
5
+ value.to_s
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Attributary
2
+ module Types
3
+ class SymbolType < Type
4
+ def self.cast_to(value)
5
+ value.to_s.to_sym
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module Attributary
2
+ VERSION = '0.1.0'.freeze
3
+ end
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: []