soulless 0.6.0 → 1.0.0
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 +4 -4
- data/.gitignore +12 -18
- data/.rspec +1 -1
- data/.travis.yml +7 -12
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +17 -13
- data/LICENSE.txt +17 -18
- data/README.md +8 -181
- data/Rakefile +4 -8
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/docker-compose.yml +11 -0
- data/lib/soulless/attributes.rb +33 -0
- data/lib/soulless/callbacks.rb +13 -0
- data/lib/soulless/dirty.rb +10 -8
- data/lib/soulless/inheritance.rb +120 -124
- data/lib/soulless/model.rb +24 -63
- data/lib/soulless/validations/uniqueness_validator.rb +7 -8
- data/lib/soulless/validations.rb +1 -2
- data/lib/soulless/version.rb +1 -1
- data/lib/soulless.rb +5 -23
- data/soulless.gemspec +12 -13
- metadata +30 -173
- data/lib/soulless/accessors.rb +0 -51
- data/lib/soulless/associations.rb +0 -35
- data/lib/soulless/locale/en.yml +0 -30
- data/lib/soulless/railtie.rb +0 -7
- data/lib/soulless/validations/associated_validator.rb +0 -17
- data/spec/associated_validator_spec.rb +0 -31
- data/spec/associations_spec.rb +0 -65
- data/spec/dirty_spec.rb +0 -54
- data/spec/dummy/.gitignore +0 -17
- data/spec/dummy/README.rdoc +0 -28
- data/spec/dummy/Rakefile +0 -6
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +0 -16
- data/spec/dummy/app/assets/stylesheets/application.css +0 -13
- data/spec/dummy/app/controllers/application_controller.rb +0 -5
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/forms/dummy_form.rb +0 -7
- data/spec/dummy/app/helpers/application_helper.rb +0 -2
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/models/dummy_model.rb +0 -6
- data/spec/dummy/app/views/layouts/application.html.erb +0 -14
- data/spec/dummy/bin/bundle +0 -3
- data/spec/dummy/bin/rails +0 -4
- data/spec/dummy/bin/rake +0 -4
- data/spec/dummy/config/application.rb +0 -28
- data/spec/dummy/config/boot.rb +0 -6
- data/spec/dummy/config/database.yml +0 -25
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -29
- data/spec/dummy/config/environments/production.rb +0 -80
- data/spec/dummy/config/environments/test.rb +0 -36
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +0 -4
- data/spec/dummy/config/initializers/inflections.rb +0 -16
- data/spec/dummy/config/initializers/mime_types.rb +0 -5
- data/spec/dummy/config/initializers/secret_token.rb +0 -12
- data/spec/dummy/config/initializers/session_store.rb +0 -3
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/spec/dummy/config/locales/en.yml +0 -23
- data/spec/dummy/config/routes.rb +0 -56
- data/spec/dummy/config.ru +0 -4
- data/spec/dummy/db/migrate/20131106221200_create_dummy_models.rb +0 -11
- data/spec/dummy/db/schema.rb +0 -24
- data/spec/dummy/db/seeds.rb +0 -7
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/lib/tasks/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +0 -58
- data/spec/dummy/public/422.html +0 -58
- data/spec/dummy/public/500.html +0 -57
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/robots.txt +0 -5
- data/spec/dummy/vendor/assets/javascripts/.keep +0 -0
- data/spec/dummy/vendor/assets/stylesheets/.keep +0 -0
- data/spec/inheritance_spec.rb +0 -51
- data/spec/soulless_spec.rb +0 -61
- data/spec/spec_helper.rb +0 -38
- data/spec/support/dummy_association.rb +0 -30
- data/spec/support/dummy_class.rb +0 -20
- data/spec/support/dummy_model_inheritance.rb +0 -10
- data/spec/support/dummy_soulless_inheritance.rb +0 -10
- data/spec/support/en.yml +0 -8
- data/spec/uniqueness_validator_spec.rb +0 -17
data/lib/soulless/inheritance.rb
CHANGED
@@ -1,139 +1,135 @@
|
|
1
1
|
module Soulless
|
2
2
|
module Inheritance
|
3
|
-
def
|
4
|
-
|
5
|
-
def inherit_from(klass, options = {})
|
6
|
-
attributes = get_attributes(klass, options)
|
3
|
+
def inherit_from(klass, options = {})
|
4
|
+
attributes = get_attributes(klass, options)
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
attributes.each do |attribute|
|
7
|
+
self.attribute(attribute[:name], attribute[:primitive], attribute[:options])
|
8
|
+
if Object.const_defined?('ActiveModel'.to_sym) && klass.ancestors.include?(ActiveModel::Validations)
|
9
|
+
setup_validators(attribute[:name], klass, options)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
14
|
+
def get_attributes(klass, options)
|
15
|
+
if klass.ancestors.include?(Virtus::Model::Core)
|
16
|
+
get_virtus_attributes(klass, options)
|
17
|
+
elsif Object.const_defined?('ActiveRecord'.to_sym) && klass.ancestors.include?(ActiveRecord::Base)
|
18
|
+
get_active_record_attributes(klass, options)
|
19
|
+
end
|
20
|
+
end
|
24
21
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
22
|
+
def get_virtus_attributes(klass, options)
|
23
|
+
attributes = []
|
24
|
+
attribute_set = klass.attribute_set
|
25
|
+
attribute_names = get_attribute_names(attribute_set.map{ |a| a.options[:name] }, options)
|
26
|
+
attribute_names.each do |attribute_name|
|
27
|
+
attribute = attribute_set[attribute_name]
|
28
|
+
if include_attribute?(attribute_name, options)
|
29
|
+
attributes << {
|
30
|
+
name: attribute_name,
|
31
|
+
primitive: attribute.primitive,
|
32
|
+
options: {
|
33
|
+
default: attribute.default_value
|
34
|
+
}
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
attributes
|
39
|
+
end
|
43
40
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
41
|
+
def get_active_record_attributes(klass, options)
|
42
|
+
attributes = []
|
43
|
+
attribute_names = get_attribute_names(klass.attribute_names.dup, options)
|
44
|
+
attribute_names.each do |attribute_name|
|
45
|
+
if include_attribute?(attribute_name, options)
|
46
|
+
column = klass.columns_hash[attribute_name.to_s]
|
47
|
+
attribute = {
|
48
|
+
name: attribute_name,
|
49
|
+
primitive: String,
|
50
|
+
options: {}
|
51
|
+
}
|
52
|
+
attribute[:primitive] = translate_primitive(column.type) if column
|
53
|
+
attribute[:options] = { default: column.default } if column &&
|
54
|
+
(options[:use_database_default] == true ||
|
55
|
+
options[:use_database_default] == attribute_name ||
|
56
|
+
(options[:use_database_default].kind_of?(Array) &&
|
57
|
+
options[:use_database_default].collect { |v| v.to_s }.include?(attribute_name)))
|
58
|
+
attributes << attribute
|
59
|
+
end
|
60
|
+
end
|
61
|
+
attributes
|
62
|
+
end
|
66
63
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
64
|
+
def setup_validators(attribute_name, klass, options)
|
65
|
+
return if skip_validators?(attribute_name, options) || !include_attribute?(attribute_name, options)
|
66
|
+
klass.validators.each do |validator|
|
67
|
+
if validator.attributes.include?(attribute_name.to_sym)
|
68
|
+
validator_class = validator.class
|
69
|
+
validator_options = {}
|
70
|
+
validator_options.merge!(validator.options)
|
71
|
+
next if validator_options.include?(:on) && options["validate_#{attribute_name}_on".to_sym] != validator_options[:on]
|
72
|
+
validator_options.delete(:on)
|
73
|
+
if validator_class.name == 'ActiveRecord::Validations::UniquenessValidator'
|
74
|
+
validator_class = Validations::UniquenessValidator
|
75
|
+
validator_options.merge!(model: klass)
|
76
|
+
else
|
77
|
+
# Validators from models are ActiveRecord
|
78
|
+
# objects which aren't useable in an
|
79
|
+
# environment without a database. It's
|
80
|
+
# necessary to convert to an ActiveModel
|
81
|
+
# validation.
|
82
|
+
if validator_class.name =~ /\AActiveRecord/
|
83
|
+
validator_class = "ActiveModel::Validations::#{validator_class.name.split('::').last}".constantize
|
84
|
+
end
|
85
|
+
end
|
86
|
+
validates_with(validator_class, { attributes: attribute_name }.merge(validator_options))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
93
90
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
91
|
+
def get_attribute_names(attributes, options)
|
92
|
+
attribute_names = attributes
|
93
|
+
attribute_names << options[:additional_attributes] if options[:additional_attributes]
|
94
|
+
attribute_names.flatten!
|
95
|
+
attribute_names.map!{ |a| a.to_s }
|
96
|
+
attribute_names
|
97
|
+
end
|
101
98
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
99
|
+
def translate_primitive(primitive)
|
100
|
+
return nil unless primitive
|
101
|
+
translated_primitive = primitive.to_s.capitalize
|
102
|
+
translated_primitive = Virtus::Attribute::Boolean if translated_primitive == 'Boolean'
|
103
|
+
translated_primitive = DateTime if translated_primitive == 'Datetime'
|
104
|
+
translated_primitive = String if translated_primitive == 'Uuid'
|
105
|
+
translated_primitive = String if translated_primitive == 'Citext'
|
106
|
+
translated_primitive = BigDecimal if translated_primitive == 'Decimal'
|
107
|
+
translated_primitive
|
108
|
+
end
|
111
109
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
110
|
+
def include_attribute?(attribute_name, options)
|
111
|
+
# Attributes we don't want to inherit
|
112
|
+
exclude_attributes = ['id']
|
113
|
+
exclude_attributes << ['created_at', 'updated_at'] unless options[:include_timestamps]
|
114
|
+
exclude_attributes << options[:exclude] if options[:exclude]
|
115
|
+
exclude_attributes.flatten!
|
116
|
+
exclude_attributes.collect!{ |v| v.to_s }
|
117
|
+
# Attributes we only want to inherit
|
118
|
+
only_attributes = []
|
119
|
+
only_attributes << options[:only] if options[:only]
|
120
|
+
only_attributes.flatten!
|
121
|
+
only_attributes.collect!{ |v| v.to_s }
|
124
122
|
|
125
|
-
|
126
|
-
|
123
|
+
!exclude_attributes.include?(attribute_name) && (only_attributes.empty? || only_attributes.include?(attribute_name))
|
124
|
+
end
|
127
125
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
end
|
136
|
-
end
|
126
|
+
def skip_validators?(attribute_name, options)
|
127
|
+
return true if options[:skip_validators] == true
|
128
|
+
skip_validators = []
|
129
|
+
skip_validators << options[:skip_validators]
|
130
|
+
skip_validators.flatten!
|
131
|
+
skip_validators.collect!{ |v| v.to_s }
|
132
|
+
skip_validators.include?(attribute_name)
|
137
133
|
end
|
138
134
|
end
|
139
135
|
end
|
data/lib/soulless/model.rb
CHANGED
@@ -1,76 +1,37 @@
|
|
1
1
|
module Soulless
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
extend ActiveModel::Translation
|
7
|
-
extend ActiveModel::Callbacks
|
8
|
-
include ActiveModel::Conversion
|
9
|
-
include ActiveModel::Dirty
|
10
|
-
include ActiveModel::Validations
|
2
|
+
class Model
|
3
|
+
extend ActiveModel::Callbacks
|
4
|
+
extend ActiveModel::Naming
|
5
|
+
extend ActiveModel::Translation
|
11
6
|
|
12
|
-
|
13
|
-
def i18n_scope
|
14
|
-
:soulless
|
15
|
-
end
|
16
|
-
end
|
7
|
+
extend Soulless::Inheritance
|
17
8
|
|
18
|
-
|
9
|
+
include ActiveModel::AttributeMethods
|
10
|
+
include ActiveModel::Dirty
|
11
|
+
include ActiveModel::SecurePassword
|
12
|
+
include ActiveModel::Serialization
|
13
|
+
include ActiveModel::Validations
|
19
14
|
|
20
|
-
|
21
|
-
|
22
|
-
super
|
23
|
-
init_dirty
|
24
|
-
end
|
15
|
+
include Soulless::Dirty
|
16
|
+
include Soulless::Validations
|
25
17
|
|
26
|
-
|
27
|
-
false
|
28
|
-
end
|
18
|
+
include Virtus.model
|
29
19
|
|
30
|
-
|
31
|
-
|
32
|
-
valid_without_callbacks?
|
33
|
-
end
|
34
|
-
end
|
20
|
+
prepend Soulless::Attributes
|
21
|
+
prepend Soulless::Callbacks
|
35
22
|
|
36
|
-
|
23
|
+
def initialize(params = {})
|
24
|
+
super
|
37
25
|
|
38
|
-
|
39
|
-
|
40
|
-
run_callbacks :save do
|
41
|
-
persist!
|
42
|
-
changes_applied
|
43
|
-
true
|
44
|
-
end
|
45
|
-
else
|
46
|
-
false
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def assign_attributes(attributes)
|
51
|
-
deep_update(self, attributes)
|
52
|
-
end
|
53
|
-
|
54
|
-
def update_attributes(attributes)
|
55
|
-
assign_attributes(attributes)
|
56
|
-
save
|
57
|
-
end
|
26
|
+
apply_changes
|
27
|
+
end
|
58
28
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
29
|
+
def i18n_scope
|
30
|
+
:soulless
|
31
|
+
end
|
63
32
|
|
64
|
-
|
65
|
-
|
66
|
-
if value.kind_of?(Hash)
|
67
|
-
deep_update(object.send(key), value)
|
68
|
-
else
|
69
|
-
object.send("#{key}=", value)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
33
|
+
def persisted?
|
34
|
+
false
|
74
35
|
end
|
75
36
|
end
|
76
37
|
end
|
@@ -5,34 +5,33 @@ module Soulless
|
|
5
5
|
raise 'ActiveRecord is not defined. The Soulless uniqueness validator cannot be used when ActiveRecord is not present.' unless Object.const_defined?('ActiveRecord')
|
6
6
|
@model = options[:model]
|
7
7
|
@attribute = options[:attribute]
|
8
|
-
options.merge!(class: @model)
|
8
|
+
options.merge!(class: @model)
|
9
9
|
@validator = ActiveRecord::Validations::UniquenessValidator.new(options)
|
10
10
|
super(options)
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def validate_each(record, attribute, value)
|
14
14
|
if !@model
|
15
15
|
raise ArgumentError, 'Missing required argument "model"'
|
16
16
|
else
|
17
17
|
record_orig, attribute_orig = record, attribute
|
18
|
-
|
18
|
+
|
19
19
|
attribute = @attribute if @attribute
|
20
20
|
record = @model.new(attribute => value)
|
21
|
-
|
22
|
-
@validator.setup(@model) if ActiveModel::VERSION::STRING < '4.1'
|
21
|
+
|
23
22
|
@validator.validate_each(record, attribute, value)
|
24
|
-
|
23
|
+
|
25
24
|
if record.errors.any?
|
26
25
|
record_orig.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(value: value))
|
27
26
|
end
|
28
27
|
end
|
29
28
|
end
|
30
29
|
end
|
31
|
-
|
30
|
+
|
32
31
|
module ClassMethods
|
33
32
|
def validates_uniqueness_of(*attr_name)
|
34
33
|
validates_with(UniquenessValidator, _merge_attributes(attr_name))
|
35
34
|
end
|
36
35
|
end
|
37
36
|
end
|
38
|
-
end
|
37
|
+
end
|
data/lib/soulless/validations.rb
CHANGED
data/lib/soulless/version.rb
CHANGED
data/lib/soulless.rb
CHANGED
@@ -1,32 +1,14 @@
|
|
1
|
-
require 'virtus'
|
2
|
-
require 'securerandom'
|
3
|
-
require 'active_support'
|
4
1
|
require 'active_model'
|
2
|
+
require 'virtus'
|
5
3
|
|
6
|
-
require 'soulless/
|
7
|
-
require 'soulless/
|
4
|
+
require 'soulless/attributes'
|
5
|
+
require 'soulless/callbacks'
|
8
6
|
require 'soulless/dirty'
|
9
7
|
require 'soulless/inheritance'
|
10
|
-
require 'soulless/model'
|
11
8
|
require 'soulless/validations'
|
9
|
+
require 'soulless/model'
|
12
10
|
require 'soulless/version'
|
13
11
|
|
14
|
-
require 'soulless/railtie' if defined?(Rails)
|
15
|
-
|
16
12
|
module Soulless
|
17
|
-
|
18
|
-
|
19
|
-
def self.model(options = {})
|
20
|
-
mod = Module.new
|
21
|
-
mod.define_singleton_method :included do |object|
|
22
|
-
object.send(:include, Virtus.model(options))
|
23
|
-
object.send(:include, Model)
|
24
|
-
object.send(:include, Associations)
|
25
|
-
object.send(:include, Validations)
|
26
|
-
object.send(:include, Dirty)
|
27
|
-
object.send(:include, Accessors)
|
28
|
-
object.send(:include, Inheritance)
|
29
|
-
end
|
30
|
-
mod
|
31
|
-
end
|
13
|
+
# Your code goes here...
|
32
14
|
end
|
data/soulless.gemspec
CHANGED
@@ -4,26 +4,25 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'soulless/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = "soulless"
|
8
8
|
spec.version = Soulless::VERSION
|
9
9
|
spec.authors = ['Anthony Smith']
|
10
10
|
spec.email = ['anthony@sticksnleaves.com']
|
11
|
-
|
12
|
-
spec.summary = %q{
|
13
|
-
spec.
|
11
|
+
|
12
|
+
spec.summary = %q{Rails models without the database (and Rails)}
|
13
|
+
spec.description = %q{Create Rails style models without the database (and Rails).}
|
14
|
+
spec.homepage = 'https://github.com/anthonator/soulless'
|
14
15
|
spec.license = 'MIT'
|
15
16
|
|
16
|
-
spec.files = `git ls-files`.split(
|
17
|
-
spec.
|
18
|
-
spec.
|
19
|
-
spec.require_paths = [
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
20
21
|
|
21
|
-
spec.
|
22
|
-
spec.
|
23
|
-
spec.add_runtime_dependency 'virtus', '>= 1.0'
|
22
|
+
spec.add_dependency 'activemodel', '>= 4.2.0', '< 5.1'
|
23
|
+
spec.add_dependency 'virtus' , '~> 1.0.0'
|
24
24
|
|
25
25
|
spec.add_development_dependency 'bundler'
|
26
|
-
spec.add_development_dependency 'database_cleaner'
|
27
26
|
spec.add_development_dependency 'rake'
|
28
|
-
spec.add_development_dependency 'rspec'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
29
28
|
end
|