trax_model 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +7 -0
  5. data/Guardfile +39 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +2 -0
  9. data/lib/trax.rb +4 -0
  10. data/lib/trax/model.rb +60 -0
  11. data/lib/trax/model/config.rb +24 -0
  12. data/lib/trax/model/freezable.rb +31 -0
  13. data/lib/trax/model/matchable.rb +31 -0
  14. data/lib/trax/model/registry.rb +33 -0
  15. data/lib/trax/model/unique_id.rb +32 -0
  16. data/lib/trax/model/uuid.rb +19 -0
  17. data/lib/trax/model/validators.rb +13 -0
  18. data/lib/trax/string.rb +5 -0
  19. data/lib/trax/validators/email_validator.rb +6 -0
  20. data/lib/trax/validators/frozen_validator.rb +7 -0
  21. data/lib/trax/validators/future_validator.rb +5 -0
  22. data/lib/trax/validators/subdomain_validator.rb +15 -0
  23. data/lib/trax/validators/url_validator.rb +10 -0
  24. data/lib/trax_model.rb +4 -0
  25. data/lib/trax_model/version.rb +3 -0
  26. data/spec/spec_helper.rb +18 -0
  27. data/spec/support/schema.rb +78 -0
  28. data/spec/trax/model/config_spec.rb +12 -0
  29. data/spec/trax/model/freezable_spec.rb +18 -0
  30. data/spec/trax/model/matchable_spec.rb +17 -0
  31. data/spec/trax/model/registry_spec.rb +17 -0
  32. data/spec/trax/model/unique_id_spec.rb +14 -0
  33. data/spec/trax/model/uuid_spec.rb +21 -0
  34. data/spec/trax/model_spec.rb +10 -0
  35. data/spec/trax/string_spec.rb +12 -0
  36. data/spec/trax/validators/email_validator_spec.rb +12 -0
  37. data/spec/trax/validators/future_validator_spec.rb +14 -0
  38. data/spec/trax/validators/subdomain_spec.rb +13 -0
  39. data/spec/trax/validators/url_validator_spec.rb +14 -0
  40. data/trax_model.gemspec +38 -0
  41. metadata +336 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 17e59a1849ad78e2b278f59a71ceef88bbf34416
4
+ data.tar.gz: 26557fe84e77a9fb2091f6f5433c4ea06da81edc
5
+ SHA512:
6
+ metadata.gz: 5f9217c38ac8bfa6e3be1236c0ea3fb0ae5bb31da21214c68b6a100da4f383c856f222c6823185e01909f707d967cd740a38e09d297860c4333198487b8a4b01
7
+ data.tar.gz: 4604d68478af8603c4168bd2aa73c71a57db9db718482806f010c6a7f92077889a4604aaac1aa9865c7f89d5e551216005f6922efb135db614cbf9c7c0b9588f
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ *.db
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+ *.bundle
20
+ *.so
21
+ *.o
22
+ *.a
23
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://8JwshTDZWLNCc53CjfAb@gem.fury.io/jasonayre/'
2
+ source 'https://rubygems.org'
3
+
4
+ gem 'trax_core', :git => 'git@github.com:jasonayre/trax_core.git'
5
+
6
+ # Specify your gem's dependencies in trax_model.gemspec
7
+ gemspec
@@ -0,0 +1,39 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :bundler do
5
+ watch('Gemfile')
6
+ # Uncomment next line if your Gemfile contains the `gemspec' command.
7
+ # watch(/^.+\.gemspec/)
8
+ end
9
+
10
+ # Note: The cmd option is now required due to the increasing number of ways
11
+ # rspec may be run, below are examples of the most common uses.
12
+ # * bundler: 'bundle exec rspec'
13
+ # * bundler binstubs: 'bin/rspec'
14
+ # * spring: 'bin/rsspec' (This will use spring if running and you have
15
+ # installed the spring binstubs per the docs)
16
+ # * zeus: 'zeus rspec' (requires the server to be started separetly)
17
+ # * 'just' rspec: 'rspec'
18
+ guard :rspec, cmd: 'bundle exec rspec' do
19
+ watch(%r{^spec/.+_spec\.rb$})
20
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
21
+ watch('spec/spec_helper.rb') { "spec" }
22
+
23
+ # Rails example
24
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
25
+ watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
26
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
27
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
28
+ watch('config/routes.rb') { "spec/routing" }
29
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
30
+ watch('spec/rails_helper.rb') { "spec" }
31
+
32
+ # Capybara features specs
33
+ watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
34
+
35
+ # Turnip features and steps
36
+ watch(%r{^spec/acceptance/(.+)\.feature$})
37
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
38
+ end
39
+
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Jason Ayre
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.
@@ -0,0 +1,29 @@
1
+ # TraxModel
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'trax_model'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install trax_model
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/trax_model/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,4 @@
1
+ require 'trax/model'
2
+ module Trax
3
+
4
+ end
@@ -0,0 +1,60 @@
1
+ require 'active_record'
2
+ require 'default_value_for'
3
+ require 'hashie/dash'
4
+ require 'hashie/mash'
5
+ require_relative './string'
6
+
7
+ require_relative './validators/email_validator'
8
+ require_relative './validators/frozen_validator'
9
+ require_relative './validators/future_validator'
10
+ require_relative './validators/subdomain_validator'
11
+ require_relative './validators/url_validator'
12
+
13
+ module Trax
14
+ module Model
15
+ extend ::ActiveSupport::Concern
16
+ extend ::ActiveSupport::Autoload
17
+
18
+ autoload :Config
19
+ autoload :Freezable
20
+ autoload :Registry
21
+ autoload :UUID
22
+ autoload :UniqueId
23
+ autoload :Matchable
24
+ autoload :Validators
25
+
26
+ include ::Trax::Model::Matchable
27
+ include ::ActiveModel::Dirty
28
+
29
+ included do
30
+ class_attribute :trax_defaults
31
+
32
+ self.trax_defaults = ::Trax::Model::Config.new
33
+
34
+ register_trax_models(self)
35
+ end
36
+
37
+
38
+ module ClassMethods
39
+ delegate :register_trax_model, :to => "::Trax::Model::Registry"
40
+ delegate :[], :to => :find
41
+
42
+
43
+ def defaults(options = {})
44
+ options.each_pair do |key, val|
45
+ self.trax_defaults.__send__("#{key}=", val)
46
+ end
47
+ end
48
+
49
+ def register_trax_models(*models)
50
+ models.each do |model|
51
+ register_trax_model(model)
52
+ end
53
+ end
54
+
55
+ def trax_registry_key
56
+ name.underscore
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,24 @@
1
+ module Trax
2
+ module Model
3
+ class Config < ::Hashie::Dash
4
+ ERROR_MESSAGES = {
5
+ :invalid_uuid_prefix => [
6
+ "UUID prefix must be 2 characters long",
7
+ "and can only include a-f0-9",
8
+ "for hexadecimal id compatibility"
9
+ ].join("\n")
10
+ }.freeze
11
+
12
+ property :uuid_prefix, :default => nil
13
+ property :uuid_column, :default => :id
14
+
15
+ def uuid_prefix=(prefix)
16
+ if prefix.length != 2 || prefix !~ /[a-f0-9]{2}/
17
+ raise ERROR_MESSAGES[:invalid_uuid_prefix]
18
+ end
19
+
20
+ self[:uuid_prefix] = prefix
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ module Trax
2
+ module Model
3
+ module Freezable
4
+ extend ::ActiveSupport::Concern
5
+
6
+ included do
7
+ class_attribute :freezable_fields
8
+ self.freezable_fields = ::ActiveSupport::OrderedOptions.new
9
+ end
10
+
11
+ module ClassMethods
12
+ def freezable_by_enum(options = {})
13
+ freezable_fields.merge!(options)
14
+
15
+ define_frozen_validators_for_enum(options)
16
+ end
17
+
18
+ def define_frozen_validators_for_enum(options)
19
+ self.class_eval do
20
+ options.each_pair do |enum_method, frozen_states|
21
+ validates_with ::FrozenValidator, :if => lambda { |record|
22
+ frozen_states.any?{ |state| state == :"#{record.send(enum_method)}" } && !record.changed.include?("#{enum_method}")
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ module Trax
2
+ module Model
3
+ module Matchable
4
+ extend ::ActiveSupport::Concern
5
+
6
+ included do
7
+ ::String.class_eval do
8
+ def to_matchable
9
+ "%#{self.strip}%"
10
+ end
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+ def matching(args = {})
16
+ matches = args.inject(self.all) do |scope, (key, value)|
17
+ node = key.is_a?(Symbol) ? self.arel_table[key] : key
18
+
19
+ values = [value]
20
+
21
+ match_values = values.flatten.compact.uniq.map!(&:to_matchable)
22
+ scope = scope.where(node.matches_any(match_values))
23
+ scope
24
+ end
25
+
26
+ matches
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ module Trax
2
+ module Model
3
+ class Registry
4
+ class_attribute :models
5
+
6
+ self.models ||= ::Hashie::Mash.new
7
+
8
+ class << self
9
+ delegate :key?, :to => :models
10
+ delegate :each, :to => :models
11
+ end
12
+
13
+ def self.register_trax_model(model)
14
+ unless models.key?(model.trax_registry_key)
15
+ models[model.trax_registry_key] = model
16
+ end
17
+ end
18
+
19
+ def self.model_type_for_uuid(str)
20
+ prefix = str[0..1]
21
+
22
+ uuid_map.fetch(prefix)
23
+ end
24
+
25
+ def self.uuid_map
26
+ @uuid_map ||= models.values.reject!{|model| !model.try(:uuid_prefix) }.inject(::Hashie::Mash.new) do |result, model|
27
+ result[model.uuid_prefix] = model
28
+ result
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ module Trax
2
+ module Model
3
+ module UniqueId
4
+ extend ::ActiveSupport::Concern
5
+
6
+ ERROR_MESSAGES = {
7
+ :invalid_uuid_prefix => [
8
+ "UUID prefix must be 2 characters long",
9
+ "and can only include a-f0-9",
10
+ "for hexadecimal id compatibility"
11
+ ].join("\n")
12
+ }.freeze
13
+
14
+ def uuid
15
+ ::Trax::Model::UUID.new(super)
16
+ end
17
+
18
+ module ClassMethods
19
+ delegate :uuid_prefix, :to => :trax_defaults
20
+ delegate :uuid_column, :to => :trax_defaults
21
+
22
+ def defaults(*args)
23
+ super(*args)
24
+
25
+ self.default_value_for(:"#{self.trax_defaults.uuid_column}") {
26
+ ::Trax::Model::UUID.generate(self.trax_defaults.uuid_prefix)
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ module Trax
2
+ module Model
3
+ class UUID < String
4
+ def self.generate(prefix = nil)
5
+ uuid = ::SecureRandom.uuid
6
+ uuid[0..1] = prefix if prefix
7
+ uuid
8
+ end
9
+
10
+ def record
11
+ @record ||= record_type ? record_type.find_by(:"#{record_type.uuid_column}" => self) : nil
12
+ end
13
+
14
+ def record_type
15
+ @record_type ||= ::Trax::Model::Registry.model_type_for_uuid(self)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ module Trax
2
+ module Model
3
+ module Validators
4
+ extend ::ActiveSupport::Autoload
5
+
6
+ autoload :EmailValidator
7
+ autoload :Frozen
8
+ autoload :FutureDate
9
+ autoload :Subdomain
10
+ autoload :UrlValidator
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ ::String.class_eval do
2
+ def uuid
3
+ self.length == 36 ? ::Trax::Model::UUID.new(self) : nil
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class EmailValidator < ActiveModel::EachValidator
2
+ def validate_each(record, attribute, value)
3
+ record.errors.add attribute, (options[:message] || "is not a valid email") unless
4
+ value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ class FrozenValidator < ActiveModel::Validator
2
+ def validate(record)
3
+ record.changed.any? do |field|
4
+ record.errors[field] << "Cannot be modified"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class FutureValidator < ActiveModel::EachValidator
2
+ def validate_each(object, attribute, value)
3
+ object.errors[attribute] << 'Must be in future' if value < ::DateTime.now
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ class SubdomainValidator < ActiveModel::EachValidator
2
+ def validate_each(object, attribute, value)
3
+ return unless value.present?
4
+ reserved_names = %w(www ftp mail pop smtp admin ssl sftp)
5
+ reserved_names = options[:reserved] if options[:reserved]
6
+
7
+ if reserved_names.include?(value)
8
+ object.errors[attribute] << 'cannot be a reserved name'
9
+ end
10
+
11
+ object.errors[attribute] << 'must have between 3 and 63 letters' unless (3..63) === value.length
12
+ object.errors[attribute] << 'cannot start or end with a hyphen' unless value =~ /^[^-].*[^-]$/i
13
+ object.errors[attribute] << 'must be alphanumeric; A-Z, 0-9 or hyphen' unless value =~ /^[a-z0-9\-]*$/i
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ class UrlValidator < ActiveModel::EachValidator
2
+ def validate_each(record, attribute, value)
3
+ record.errors[attribute] << (options[:message] || "must be a valid URL") unless url_valid?(value)
4
+ end
5
+
6
+ def url_valid?(url)
7
+ url = URI.parse(url) rescue false
8
+ url.kind_of?(URI::HTTP) || url.kind_of?(URI::HTTPS)
9
+ end
10
+ end
@@ -0,0 +1,4 @@
1
+ require 'trax'
2
+
3
+ module TraxModel
4
+ end
@@ -0,0 +1,3 @@
1
+ module TraxModel
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'simplecov'
4
+ require 'pry'
5
+ require 'trax_model'
6
+
7
+ SimpleCov.start do
8
+ add_filter '/spec/'
9
+ end
10
+
11
+ RSpec.configure do |config|
12
+ config.before(:suite) do
13
+ end
14
+ end
15
+
16
+ Bundler.require(:default, :development, :test)
17
+
18
+ ::Dir["#{::File.dirname(__FILE__)}/support/*.rb"].each {|f| require f }
@@ -0,0 +1,78 @@
1
+ require 'active_record'
2
+
3
+ ActiveRecord::Base.establish_connection(
4
+ :adapter => "sqlite3",
5
+ :database => "spec/test.db"
6
+ )
7
+
8
+ ActiveRecord::Base.connection.tables.each do |table|
9
+ ActiveRecord::Base.connection.drop_table(table)
10
+ end
11
+
12
+ ActiveRecord::Schema.define(:version => 1) do
13
+ create_table "products", :force => true do |t|
14
+ t.string "name"
15
+ t.integer "category_id"
16
+ t.integer "user_id"
17
+ t.decimal "price"
18
+ t.integer "in_stock_quantity"
19
+ t.integer "on_order_quantity"
20
+ t.boolean "active"
21
+ t.string "uuid"
22
+ t.datetime "created_at", :null => false
23
+ t.datetime "updated_at", :null => false
24
+ end
25
+
26
+ create_table "messages", :force => true do |t|
27
+ t.string "title"
28
+ t.text "body"
29
+ t.integer "status"
30
+ t.string "uuid"
31
+ t.datetime "deliver_at"
32
+ t.datetime "created_at", :null => false
33
+ t.datetime "updated_at", :null => false
34
+ end
35
+
36
+ create_table "widgets", :force => true do |t|
37
+ t.string "email_address"
38
+ t.string "subdomain"
39
+ t.string "website"
40
+ t.integer "status"
41
+ t.datetime "created_at", :null => false
42
+ t.datetime "updated_at", :null => false
43
+ end
44
+ end
45
+
46
+ class Product < ::ActiveRecord::Base
47
+ include ::Trax::Model
48
+ include ::Trax::Model::UniqueId
49
+
50
+ defaults :uuid_prefix => "a1", :uuid_column => "uuid"
51
+ end
52
+
53
+ class Widget < ::ActiveRecord::Base
54
+ include ::Trax::Model
55
+
56
+ defaults :uuid_prefix => "a2", :uuid_column => "uuid"
57
+
58
+ validates :subdomain, :subdomain => true, :allow_nil => true
59
+ validates :email_address, :email => true, :allow_nil => true
60
+ validates :website, :url => true, :allow_nil => true
61
+ end
62
+
63
+ class Message < ::ActiveRecord::Base
64
+ include ::Trax::Model
65
+ include ::Trax::Model::Freezable
66
+
67
+ defaults :uuid_prefix => "a3", :uuid_column => "uuid"
68
+
69
+ enum :status => [:queued, :scheduled, :delivered, :failed_delivery]
70
+
71
+ default_value_for :status do
72
+ self.statuses[:queued]
73
+ end
74
+
75
+ validates :deliver_at, :future => true, :allow_nil => true
76
+
77
+ freezable_by_enum :status => [:delivered, :failed_delivery]
78
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ describe ::Trax::Model::Config do
3
+ describe "uuid_prefix" do
4
+ context "bad prefixes" do
5
+ ["a", "1p", "a1a", "bl", "1", "111"].each do |prefix|
6
+ it "raises error when passed hex incompatible prefix #{prefix}" do
7
+ expect{ described_class.new(:uuid_prefix => prefix).to_raise_error }
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Trax::Model::Freezable do
4
+ subject{ ::Message.create(:title => "Whatever") }
5
+
6
+ its(:status) { should eq "queued" }
7
+
8
+ context "in frozen state" do
9
+ subject { ::Message.create(:title => "Whatever", :status => :delivered) }
10
+
11
+ it do
12
+ subject.title = "somethingelse"
13
+ subject.save
14
+
15
+ subject.errors.messages[:title].should include("Cannot be modified")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ describe ::Trax::Model::Matchable do
3
+ let(:product) { ::Product.create(:name => "27 inch iMac") }
4
+ subject{ product }
5
+
6
+ describe ".matching" do
7
+ it('does a like lookup') do
8
+ Product.matching(:name => "imac").to_sql.should include("LIKE '%imac%'")
9
+ end
10
+
11
+ ["imac", "ima", "INCH IMAC", "27"].each do |keyword|
12
+ it "#{keyword} should return match" do
13
+ Product.matching(:name => keyword).should include subject
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Trax::Model::Registry do
4
+ subject{ described_class }
5
+
6
+ its(:models) { should be_instance_of(::Hashie::Mash) }
7
+ its(:uuid_map) { should have_key("a1") }
8
+ its(:uuid_map) { should be_instance_of(::Hashie::Mash) }
9
+
10
+ it "should have registered product model" do
11
+ subject.key?(:product).should be true
12
+ end
13
+
14
+ it "model_type_for_uuid" do
15
+ subject.model_type_for_uuid("a1asdasdasd").should eq Product
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+ describe ::Trax::Model::UniqueId do
3
+ subject{ ::Product }
4
+
5
+ describe "uuid_prefix" do
6
+ context "bad prefixes" do
7
+ ["a", "1p", "a1a", "bl", "1", "111"].each do |prefix|
8
+ it "raises error when passed hex incompatible prefix #{prefix}" do
9
+ expect{ subject.trax_defaults.uuid_prefix=(prefix) }.to raise_error
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Trax::Model::UUID do
4
+ let(:product) { ::Product.create(:name => "iMac") }
5
+ subject{ product.uuid }
6
+
7
+ its(:record_type) { should eq ::Product }
8
+ its(:record) { should eq product }
9
+
10
+ describe ".generate" do
11
+ context "with prefix" do
12
+ let(:prefixed_uuid) { described_class.generate("1a") }
13
+ it { prefixed_uuid[0..1].should eq "1a" }
14
+ end
15
+
16
+ context "without prefix" do
17
+ let(:unprefixed_uuid) { described_class.generate }
18
+ it { unprefixed_uuid.length.should eq 36 }
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Trax::Model do
4
+ subject do
5
+ ::Product
6
+ end
7
+
8
+ its(:trax_registry_key) { should eq "product" }
9
+ its(:trax_defaults) { should be_a(::Trax::Model::Config) }
10
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ describe ::String do
3
+ let(:product) { ::Product.create(:name => "iMac") }
4
+ subject{ "#{product.uuid}" }
5
+
6
+ its(:uuid) { should be_instance_of(::Trax::Model::UUID) }
7
+
8
+ context "when not a uuid length" do
9
+ let(:truncated_uuid) { subject[0..8] }
10
+ it { truncated_uuid.uuid.should be_nil }
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::EmailValidator do
4
+ subject { ::Widget.create(:email_address => "lumbergh@initech.com") }
5
+
6
+ ["bill@somewhere", "bill", "@initech.com", "!!!@!!!.com"].each do |bad_email|
7
+ it "should fail validation for #{bad_email}" do
8
+ widget = ::Widget.create(:email_address => bad_email)
9
+ widget.valid?.should eq false
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::FutureValidator do
4
+ subject { ::Message.create(:deliver_at => (::DateTime.now + 1.days)) }
5
+
6
+ its(:valid?) { should eq true }
7
+
8
+ [(DateTime.now - 1.days)].each do |past_date|
9
+ it "should fail validation for #{past_date}" do
10
+ widget = ::Message.create(:deliver_at => past_date)
11
+ widget.errors.messages.should have_key(:deliver_at)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::SubdomainValidator do
4
+ subject { ::Widget.create(:subdomain => "something") }
5
+ its(:valid?) { should eq true }
6
+
7
+ ["bad!", "-asdasd", "www", "ac"].each do |bad_subdomain|
8
+ it "should fail validation for #{bad_subdomain}" do
9
+ widget = ::Widget.create(:subdomain => bad_subdomain)
10
+ widget.valid?.should eq false
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::UrlValidator do
4
+ subject { ::Widget.create(:website => "http://www.initech.com") }
5
+
6
+ its(:valid?) { should eq true }
7
+
8
+ ["www.initech.com", "http://www.initech.com!"].each do |bad_url|
9
+ it "should fail validation for #{bad_url}" do
10
+ widget = ::Widget.create(:website => bad_url)
11
+ widget.errors.messages.should have_key(:website)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'trax_model/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "trax_model"
8
+ spec.version = TraxModel::VERSION
9
+ spec.authors = ["Jason Ayre"]
10
+ spec.email = ["jasonayre@gmail.com"]
11
+ spec.summary = %q{Higher level ActiveRecord models for rails}
12
+ spec.description = %q{Supports uuid defaults and mapping, default attributes, and various other utilities via composition}
13
+ spec.homepage = "http://github.com/jasonayre/trax_model"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
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"]
20
+
21
+ spec.add_dependency "trax_core"
22
+ spec.add_dependency "default_value_for", "~> 3.0.0"
23
+ spec.add_development_dependency "activerecord"
24
+ spec.add_development_dependency "bundler", "~> 1.6"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "sqlite3"
27
+ spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency "rspec-pride"
29
+ spec.add_development_dependency "pry-nav"
30
+ spec.add_development_dependency "simplecov"
31
+ spec.add_development_dependency 'rspec-its', '~> 1'
32
+ spec.add_development_dependency 'rspec-collection_matchers', '~> 1'
33
+ spec.add_development_dependency 'guard', '~> 2'
34
+ spec.add_development_dependency 'guard-rspec', '~> 4'
35
+ spec.add_development_dependency 'guard-bundler', '~> 2'
36
+ spec.add_development_dependency 'rb-fsevent'
37
+ spec.add_development_dependency 'terminal-notifier-guard'
38
+ end
metadata ADDED
@@ -0,0 +1,336 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trax_model
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jason Ayre
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: trax_core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: default_value_for
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 3.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 3.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: activerecord
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.6'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec-pride
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pry-nav
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rspec-its
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '1'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '1'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rspec-collection_matchers
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '1'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '1'
181
+ - !ruby/object:Gem::Dependency
182
+ name: guard
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '2'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '2'
195
+ - !ruby/object:Gem::Dependency
196
+ name: guard-rspec
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: '4'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: '4'
209
+ - !ruby/object:Gem::Dependency
210
+ name: guard-bundler
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: '2'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: '2'
223
+ - !ruby/object:Gem::Dependency
224
+ name: rb-fsevent
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
237
+ - !ruby/object:Gem::Dependency
238
+ name: terminal-notifier-guard
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '0'
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
251
+ description: Supports uuid defaults and mapping, default attributes, and various other
252
+ utilities via composition
253
+ email:
254
+ - jasonayre@gmail.com
255
+ executables: []
256
+ extensions: []
257
+ extra_rdoc_files: []
258
+ files:
259
+ - ".gitignore"
260
+ - ".rspec"
261
+ - Gemfile
262
+ - Guardfile
263
+ - LICENSE.txt
264
+ - README.md
265
+ - Rakefile
266
+ - lib/trax.rb
267
+ - lib/trax/model.rb
268
+ - lib/trax/model/config.rb
269
+ - lib/trax/model/freezable.rb
270
+ - lib/trax/model/matchable.rb
271
+ - lib/trax/model/registry.rb
272
+ - lib/trax/model/unique_id.rb
273
+ - lib/trax/model/uuid.rb
274
+ - lib/trax/model/validators.rb
275
+ - lib/trax/string.rb
276
+ - lib/trax/validators/email_validator.rb
277
+ - lib/trax/validators/frozen_validator.rb
278
+ - lib/trax/validators/future_validator.rb
279
+ - lib/trax/validators/subdomain_validator.rb
280
+ - lib/trax/validators/url_validator.rb
281
+ - lib/trax_model.rb
282
+ - lib/trax_model/version.rb
283
+ - spec/spec_helper.rb
284
+ - spec/support/schema.rb
285
+ - spec/trax/model/config_spec.rb
286
+ - spec/trax/model/freezable_spec.rb
287
+ - spec/trax/model/matchable_spec.rb
288
+ - spec/trax/model/registry_spec.rb
289
+ - spec/trax/model/unique_id_spec.rb
290
+ - spec/trax/model/uuid_spec.rb
291
+ - spec/trax/model_spec.rb
292
+ - spec/trax/string_spec.rb
293
+ - spec/trax/validators/email_validator_spec.rb
294
+ - spec/trax/validators/future_validator_spec.rb
295
+ - spec/trax/validators/subdomain_spec.rb
296
+ - spec/trax/validators/url_validator_spec.rb
297
+ - trax_model.gemspec
298
+ homepage: http://github.com/jasonayre/trax_model
299
+ licenses:
300
+ - MIT
301
+ metadata: {}
302
+ post_install_message:
303
+ rdoc_options: []
304
+ require_paths:
305
+ - lib
306
+ required_ruby_version: !ruby/object:Gem::Requirement
307
+ requirements:
308
+ - - ">="
309
+ - !ruby/object:Gem::Version
310
+ version: '0'
311
+ required_rubygems_version: !ruby/object:Gem::Requirement
312
+ requirements:
313
+ - - ">="
314
+ - !ruby/object:Gem::Version
315
+ version: '0'
316
+ requirements: []
317
+ rubyforge_project:
318
+ rubygems_version: 2.2.2
319
+ signing_key:
320
+ specification_version: 4
321
+ summary: Higher level ActiveRecord models for rails
322
+ test_files:
323
+ - spec/spec_helper.rb
324
+ - spec/support/schema.rb
325
+ - spec/trax/model/config_spec.rb
326
+ - spec/trax/model/freezable_spec.rb
327
+ - spec/trax/model/matchable_spec.rb
328
+ - spec/trax/model/registry_spec.rb
329
+ - spec/trax/model/unique_id_spec.rb
330
+ - spec/trax/model/uuid_spec.rb
331
+ - spec/trax/model_spec.rb
332
+ - spec/trax/string_spec.rb
333
+ - spec/trax/validators/email_validator_spec.rb
334
+ - spec/trax/validators/future_validator_spec.rb
335
+ - spec/trax/validators/subdomain_spec.rb
336
+ - spec/trax/validators/url_validator_spec.rb