soulless 0.6.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +12 -18
  3. data/.rspec +1 -1
  4. data/.travis.yml +7 -12
  5. data/CODE_OF_CONDUCT.md +49 -0
  6. data/Gemfile +17 -13
  7. data/LICENSE.txt +17 -18
  8. data/README.md +8 -181
  9. data/Rakefile +4 -8
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/docker-compose.yml +11 -0
  13. data/lib/soulless/attributes.rb +33 -0
  14. data/lib/soulless/callbacks.rb +13 -0
  15. data/lib/soulless/dirty.rb +10 -8
  16. data/lib/soulless/inheritance.rb +120 -124
  17. data/lib/soulless/model.rb +24 -63
  18. data/lib/soulless/validations/uniqueness_validator.rb +7 -8
  19. data/lib/soulless/validations.rb +1 -2
  20. data/lib/soulless/version.rb +1 -1
  21. data/lib/soulless.rb +5 -23
  22. data/soulless.gemspec +12 -13
  23. metadata +30 -173
  24. data/lib/soulless/accessors.rb +0 -51
  25. data/lib/soulless/associations.rb +0 -35
  26. data/lib/soulless/locale/en.yml +0 -30
  27. data/lib/soulless/railtie.rb +0 -7
  28. data/lib/soulless/validations/associated_validator.rb +0 -17
  29. data/spec/associated_validator_spec.rb +0 -31
  30. data/spec/associations_spec.rb +0 -65
  31. data/spec/dirty_spec.rb +0 -54
  32. data/spec/dummy/.gitignore +0 -17
  33. data/spec/dummy/README.rdoc +0 -28
  34. data/spec/dummy/Rakefile +0 -6
  35. data/spec/dummy/app/assets/images/.keep +0 -0
  36. data/spec/dummy/app/assets/javascripts/application.js +0 -16
  37. data/spec/dummy/app/assets/stylesheets/application.css +0 -13
  38. data/spec/dummy/app/controllers/application_controller.rb +0 -5
  39. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  40. data/spec/dummy/app/forms/dummy_form.rb +0 -7
  41. data/spec/dummy/app/helpers/application_helper.rb +0 -2
  42. data/spec/dummy/app/mailers/.keep +0 -0
  43. data/spec/dummy/app/models/.keep +0 -0
  44. data/spec/dummy/app/models/concerns/.keep +0 -0
  45. data/spec/dummy/app/models/dummy_model.rb +0 -6
  46. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  47. data/spec/dummy/bin/bundle +0 -3
  48. data/spec/dummy/bin/rails +0 -4
  49. data/spec/dummy/bin/rake +0 -4
  50. data/spec/dummy/config/application.rb +0 -28
  51. data/spec/dummy/config/boot.rb +0 -6
  52. data/spec/dummy/config/database.yml +0 -25
  53. data/spec/dummy/config/environment.rb +0 -5
  54. data/spec/dummy/config/environments/development.rb +0 -29
  55. data/spec/dummy/config/environments/production.rb +0 -80
  56. data/spec/dummy/config/environments/test.rb +0 -36
  57. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  58. data/spec/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  59. data/spec/dummy/config/initializers/inflections.rb +0 -16
  60. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  61. data/spec/dummy/config/initializers/secret_token.rb +0 -12
  62. data/spec/dummy/config/initializers/session_store.rb +0 -3
  63. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  64. data/spec/dummy/config/locales/en.yml +0 -23
  65. data/spec/dummy/config/routes.rb +0 -56
  66. data/spec/dummy/config.ru +0 -4
  67. data/spec/dummy/db/migrate/20131106221200_create_dummy_models.rb +0 -11
  68. data/spec/dummy/db/schema.rb +0 -24
  69. data/spec/dummy/db/seeds.rb +0 -7
  70. data/spec/dummy/db/test.sqlite3 +0 -0
  71. data/spec/dummy/lib/assets/.keep +0 -0
  72. data/spec/dummy/lib/tasks/.keep +0 -0
  73. data/spec/dummy/log/.keep +0 -0
  74. data/spec/dummy/public/404.html +0 -58
  75. data/spec/dummy/public/422.html +0 -58
  76. data/spec/dummy/public/500.html +0 -57
  77. data/spec/dummy/public/favicon.ico +0 -0
  78. data/spec/dummy/public/robots.txt +0 -5
  79. data/spec/dummy/vendor/assets/javascripts/.keep +0 -0
  80. data/spec/dummy/vendor/assets/stylesheets/.keep +0 -0
  81. data/spec/inheritance_spec.rb +0 -51
  82. data/spec/soulless_spec.rb +0 -61
  83. data/spec/spec_helper.rb +0 -38
  84. data/spec/support/dummy_association.rb +0 -30
  85. data/spec/support/dummy_class.rb +0 -20
  86. data/spec/support/dummy_model_inheritance.rb +0 -10
  87. data/spec/support/dummy_soulless_inheritance.rb +0 -10
  88. data/spec/support/en.yml +0 -8
  89. data/spec/uniqueness_validator_spec.rb +0 -17
@@ -1,139 +1,135 @@
1
1
  module Soulless
2
2
  module Inheritance
3
- def self.included(base)
4
- base.instance_eval do
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
- attributes.each do |attribute|
9
- self.attribute(attribute[:name], attribute[:primitive], attribute[:options])
10
- if Object.const_defined?('ActiveModel'.to_sym) && klass.ancestors.include?(ActiveModel::Validations)
11
- setup_validators(attribute[:name], klass, options)
12
- end
13
- end
14
- end
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
- private
17
- def get_attributes(klass, options)
18
- if klass.ancestors.include?(Virtus::Model::Core)
19
- get_virtus_attributes(klass, options)
20
- elsif Object.const_defined?('ActiveRecord'.to_sym) && klass.ancestors.include?(ActiveRecord::Base)
21
- get_active_record_attributes(klass, options)
22
- end
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
- def get_virtus_attributes(klass, options)
26
- attributes = []
27
- attribute_set = klass.attribute_set
28
- attribute_names = get_attribute_names(attribute_set.map{ |a| a.options[:name] }, options)
29
- attribute_names.each do |attribute_name|
30
- attribute = attribute_set[attribute_name]
31
- if include_attribute?(attribute_name, options)
32
- attributes << {
33
- name: attribute_name,
34
- primitive: attribute.primitive,
35
- options: {
36
- default: attribute.default_value
37
- }
38
- }
39
- end
40
- end
41
- attributes
42
- end
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
- def get_active_record_attributes(klass, options)
45
- attributes = []
46
- attribute_names = get_attribute_names(klass.attribute_names.dup, options)
47
- attribute_names.each do |attribute_name|
48
- if include_attribute?(attribute_name, options)
49
- column = klass.columns_hash[attribute_name.to_s]
50
- attribute = {
51
- name: attribute_name,
52
- primitive: String,
53
- options: {}
54
- }
55
- attribute[:primitive] = translate_primitive(column.type) if column
56
- attribute[:options] = { default: column.default } if column &&
57
- (options[:use_database_default] == true ||
58
- options[:use_database_default] == attribute_name ||
59
- (options[:use_database_default].kind_of?(Array) &&
60
- options[:use_database_default].collect { |v| v.to_s }.include?(attribute_name)))
61
- attributes << attribute
62
- end
63
- end
64
- attributes
65
- end
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
- def setup_validators(attribute_name, klass, options)
68
- return if skip_validators?(attribute_name, options) || !include_attribute?(attribute_name, options)
69
- klass.validators.each do |validator|
70
- if validator.attributes.include?(attribute_name.to_sym)
71
- validator_class = validator.class
72
- validator_options = {}
73
- validator_options.merge!(validator.options)
74
- next if validator_options.include?(:on) && options["validate_#{attribute_name}_on".to_sym] != validator_options[:on]
75
- validator_options.delete(:on)
76
- if validator_class == ActiveRecord::Validations::UniquenessValidator
77
- validator_class = Validations::UniquenessValidator
78
- validator_options.merge!(model: klass)
79
- else
80
- # Validators from models are ActiveRecord
81
- # objects which aren't useable in an
82
- # environment without a database. It's
83
- # necessary to convert to an ActiveModel
84
- # validation.
85
- if validator_class.name =~ /\AActiveRecord/
86
- validator_class = "ActiveModel::Validations::#{validator_class.name.split('::').last}".constantize
87
- end
88
- end
89
- validates_with(validator_class, { attributes: attribute_name }.merge(validator_options))
90
- end
91
- end
92
- end
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
- def get_attribute_names(attributes, options)
95
- attribute_names = attributes
96
- attribute_names << options[:additional_attributes] if options[:additional_attributes]
97
- attribute_names.flatten!
98
- attribute_names.map!{ |a| a.to_s }
99
- attribute_names
100
- end
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
- def translate_primitive(primitive)
103
- return nil unless primitive
104
- translated_primitive = primitive.to_s.capitalize
105
- translated_primitive = Virtus::Attribute::Boolean if translated_primitive == 'Boolean'
106
- translated_primitive = DateTime if translated_primitive == 'Datetime'
107
- translated_primitive = String if translated_primitive == 'Uuid'
108
- translated_primitive = BigDecimal if translated_primitive == 'Decimal'
109
- translated_primitive
110
- end
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
- def include_attribute?(attribute_name, options)
113
- # Attributes we don't want to inherit
114
- exclude_attributes = ['id']
115
- exclude_attributes << ['created_at', 'updated_at'] unless options[:include_timestamps]
116
- exclude_attributes << options[:exclude] if options[:exclude]
117
- exclude_attributes.flatten!
118
- exclude_attributes.collect!{ |v| v.to_s }
119
- # Attributes we only want to inherit
120
- only_attributes = []
121
- only_attributes << options[:only] if options[:only]
122
- only_attributes.flatten!
123
- only_attributes.collect!{ |v| v.to_s }
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
- !exclude_attributes.include?(attribute_name) && (only_attributes.empty? || only_attributes.include?(attribute_name))
126
- end
123
+ !exclude_attributes.include?(attribute_name) && (only_attributes.empty? || only_attributes.include?(attribute_name))
124
+ end
127
125
 
128
- def skip_validators?(attribute_name, options)
129
- return true if options[:skip_validators] == true
130
- skip_validators = []
131
- skip_validators << options[:skip_validators]
132
- skip_validators.flatten!
133
- skip_validators.collect!{ |v| v.to_s }
134
- skip_validators.include?(attribute_name)
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
@@ -1,76 +1,37 @@
1
1
  module Soulless
2
- module Model
3
- def self.included(base)
4
- base.class_eval do
5
- extend ActiveModel::Naming
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
- class << self
13
- def i18n_scope
14
- :soulless
15
- end
16
- end
7
+ extend Soulless::Inheritance
17
8
 
18
- define_model_callbacks :validation, :save
9
+ include ActiveModel::AttributeMethods
10
+ include ActiveModel::Dirty
11
+ include ActiveModel::SecurePassword
12
+ include ActiveModel::Serialization
13
+ include ActiveModel::Validations
19
14
 
20
- def initialize(params = {})
21
- init_accessors(attribute_set.map { |a| a.name })
22
- super
23
- init_dirty
24
- end
15
+ include Soulless::Dirty
16
+ include Soulless::Validations
25
17
 
26
- def persisted?
27
- false
28
- end
18
+ include Virtus.model
29
19
 
30
- def valid_with_callbacks?
31
- run_callbacks :validation do
32
- valid_without_callbacks?
33
- end
34
- end
20
+ prepend Soulless::Attributes
21
+ prepend Soulless::Callbacks
35
22
 
36
- alias_method_chain :valid?, :callbacks
23
+ def initialize(params = {})
24
+ super
37
25
 
38
- def save
39
- if valid?
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
- private
60
- def persist!
61
- raise 'Method persist! not defined...'
62
- end
29
+ def i18n_scope
30
+ :soulless
31
+ end
63
32
 
64
- def deep_update(object, attributes)
65
- attributes.each do |key, value|
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) if ActiveModel::VERSION::STRING >= '4.1.0'
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
@@ -1,4 +1,3 @@
1
- require 'soulless/validations/associated_validator'
2
1
  require 'soulless/validations/uniqueness_validator'
3
2
 
4
3
  module Soulless
@@ -7,4 +6,4 @@ module Soulless
7
6
  base.send(:extend, ClassMethods)
8
7
  end
9
8
  end
10
- end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module Soulless
2
- VERSION = "0.6.0"
2
+ VERSION = '1.0.0'
3
3
  end
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/accessors'
7
- require 'soulless/associations'
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
- I18n.load_path += Dir.glob('lib/soulless/locale/*.{rb,yml}')
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 = 'soulless'
7
+ spec.name = "soulless"
8
8
  spec.version = Soulless::VERSION
9
9
  spec.authors = ['Anthony Smith']
10
10
  spec.email = ['anthony@sticksnleaves.com']
11
- spec.description = %q{Rails models without a database (and Rails).}
12
- spec.summary = %q{Create Rails style models without the database.}
13
- spec.homepage = ''
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.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ['lib']
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.add_runtime_dependency 'activesupport', '>= 3.2'
22
- spec.add_runtime_dependency 'activemodel', '>= 3.2'
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