uuids 4.0.1 → 4.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ce0188d48ab948a1a9d6e01b9bce6783d7d05f4
4
- data.tar.gz: 55040c5ebc0e3824e2e81c5eb05806544dea305e
3
+ metadata.gz: 016e522c63a1b3f96e575a5e3cc46ebf45d4b7f8
4
+ data.tar.gz: a23f8b1dc1bbc0e4588294ca6537526bec02d8cf
5
5
  SHA512:
6
- metadata.gz: 0980d73961b09197aa7e419de79d880fcee3966b552eb1d7e31fad42aab546973479bac2a6321ebc71242150934378cc4a42b5041d709a6e7c807a355cabb1f3
7
- data.tar.gz: c1eb2d45b66ebfdde301d6c4c31b2dc357a53447fc02754395ed88fea18caeb4f4c12ea67ca916e78b4032e3de9006bf9c63fb172f9ac7a098422ec23a12ab9b
6
+ metadata.gz: 1265400e53725494f22c2a31b4c90de117a8caa5bc16e415aedf3732ddaac2d4ef403268f65a7ff1544f9c65421b5d9b6586abc51ffc3f95c56edceeb58457f5
7
+ data.tar.gz: e635c00cf24e8c160723d7c9c2716014ec4199f0abfb90966f45685fdcdabcf010a42e7cab3bce6edb662b20821cbf33ab47d0f8ec61c0531b2618584ff82399
data/.rubocop.yml CHANGED
@@ -29,6 +29,9 @@ Style/Documentation:
29
29
  - 'db/**/*'
30
30
  - 'lib/uuids/version.rb'
31
31
 
32
+ Style/EmptyLinesAroundBlockBody:
33
+ Enabled: false
34
+
32
35
  Style/EmptyLinesAroundClassBody:
33
36
  Enabled: false
34
37
 
@@ -39,8 +42,7 @@ Style/EmptyLinesAroundModuleBody:
39
42
  Enabled: false
40
43
 
41
44
  Style/EmptyLineBetweenDefs:
42
- Exclude:
43
- - 'spec/**/*'
45
+ Enabled: false
44
46
 
45
47
  Style/PredicateName:
46
48
  Enabled: false
data/README.rdoc CHANGED
@@ -60,24 +60,18 @@ Or install it yourself as:
60
60
 
61
61
  $ gem install uuids
62
62
 
63
- == Initialization
64
-
65
- After installation you should copy and run uuid's db migration into your module.
66
-
67
- When you install the module to a final application, the migration should be
68
- installed to `db/migrate` path directly.
63
+ Then run the command in the root of a <b>end-up application</b>:
69
64
 
70
65
  $ uuids install
71
66
 
72
- When you install the module to another gem as a part of its environment,
73
- the migration isn't a part of your project. It only needed for testing
74
- your gem in a proper environment.
75
-
76
- In this case the migration should be installed to a dummy app in a
77
- `spec/dummy/db/migrate` folder. Do it with the `-d` key:
67
+ Use the <tt>-d</tt> key when installing the gem into a <b>module</b> that is not
68
+ an end-up application (Rails engine etc.):
78
69
 
79
70
  $ uuids install -d
80
71
 
72
+ (this will copy the gem's migrations to the host's dummy folder:
73
+ +spec/dummy/db/migrate+).
74
+
81
75
  == Usage
82
76
 
83
77
  === Adding UUIDs to models
@@ -86,6 +80,7 @@ Add the assotiation to your AR model with a `has_uuids` helper:
86
80
 
87
81
  class City < ActiveRecord::Base
88
82
  include Uuids::Base
83
+
89
84
  has_uuids
90
85
  end
91
86
 
@@ -113,9 +108,6 @@ all object's UUIDs to another record in advance.
113
108
 
114
109
  === Referring model by UUID
115
110
 
116
- Instead of <tt>ActiveRecord::Associations</tt> +belongs_to+, +has_one+ and
117
- +has_many+, you should define custom methods explicitly.
118
-
119
111
  # db/migrate/*_create_streets.rb
120
112
  class CreateStreetsTable < ActiveRecord::Migration
121
113
  def change
@@ -128,17 +120,17 @@ Instead of <tt>ActiveRecord::Associations</tt> +belongs_to+, +has_one+ and
128
120
 
129
121
  # app/models/street.rb
130
122
  class Street < ActiveRecord::Base
123
+ include Uuids::Base
131
124
 
132
- scope :by_city, ->(city) { City.by_uuid(city.uuid) }
125
+ belongs_by_uuid_to :city, class: City
126
+ end
133
127
 
134
- def city
135
- @city ||= City.by_uuid(city_uuid)
136
- end
128
+ This will add both getter and setter for the attribute:
137
129
 
138
- def city=(city)
139
- write_attribute :city_uuid, city.uuid
140
- end
141
- end
130
+ street = Street.new name: "Damrak", city: City.new name: "Amsterdam"
131
+ street.city
132
+ # => #<City @name="Amsterdam" ... >
133
+ street.city_uuid == street.city.uuid # => true
142
134
 
143
135
  === Adding uuid
144
136
 
@@ -41,7 +41,8 @@ module Uuids
41
41
  end
42
42
 
43
43
  # @api hide
44
- # Runs and returns the query.
44
+ # Runs and returns the query
45
+ # @return [ActiveRecord::Relation] The updated scope.
45
46
  def select
46
47
  values.any? ? by_uuid : model.all
47
48
  end
@@ -0,0 +1,123 @@
1
+ module Uuids
2
+ module Base
3
+
4
+ # @api hide
5
+ # Adds getter and setter for the model attribute referred by uuid.
6
+ #
7
+ # @example
8
+ # BelongsTo.add City, :state, State
9
+ # city = City.new
10
+ # city.respond_to? :state # => true
11
+ # city.respond_to? :state= # => true
12
+ class BelongsTo < Struct.new(:klass, :name, :model)
13
+
14
+ # @api hide
15
+ # @!attribute klass
16
+ # The model to add the attribute to.
17
+ # @return [ActiveRecord::Base] The model class.
18
+
19
+ # @api hide
20
+ # @!attribute name
21
+ # The name of the attribute to be added.
22
+ # @return [String, Symbol] The name.
23
+
24
+ # @api hide
25
+ # @!attribute model
26
+ # The model to be referred by uuid.
27
+ # @return [ActiveRecord::Base] The model class to be referred to.
28
+
29
+ # @api hide
30
+ # @!attribute [r] class_name
31
+ # The name of the {#klass} constant.
32
+ # @return [String] The {#klass} name.
33
+ def class_name
34
+ @class_name ||= klass.name
35
+ end
36
+
37
+ # @api hide
38
+ # @!attribute [r] model_name
39
+ # The name of the {#model} constant.
40
+ # @return [String] The {#model} name.
41
+ def model_name
42
+ @model_name ||= model.name
43
+ end
44
+
45
+ # @api hide
46
+ # @!attribute [r] model_name
47
+ # The name of the {#klass} db table column to store reference to the
48
+ # attribute by uuid.
49
+ # @return [String] The name of the column.
50
+ def column_name
51
+ @column_name ||= "#{ name }_uuid"
52
+ end
53
+
54
+ # @api hide
55
+ # Constructs the object and adds the attribute.
56
+ # @example (see Uuids::Base::BelongsTo)
57
+ # @params [ActiveRecord::Base] klass The model to add attribute to.
58
+ # Should have a corresponding column for reference by uuid.
59
+ # @params [String, Symbol] name The name of the attribute to be added.
60
+ # @params [ActiveRecord::Base] model The model to be referred by uuid.
61
+ # Should include the <tt>Uuids::Base</tt> module.
62
+ # @raise (see Uuids::Base::BelongsTo#add)
63
+ def self.add(*args)
64
+ new(*args).add
65
+ end
66
+
67
+ # @api hide
68
+ # Adds the attribute's getter and setter.
69
+ # @raise [TypeError] if the {#model} doesn't include
70
+ # the <tt>Uuids::Base</tt> module.
71
+ # @raise [NotImplementedError] if the {#klass} doesn't have the
72
+ # correspondint {#column_name} column.
73
+ def add
74
+ check_model
75
+ check_column
76
+ add_getter
77
+ add_setter
78
+ end
79
+
80
+ private
81
+
82
+ def check_model
83
+ return if model.ancestors.include? Uuids::Base
84
+ fail TypeError
85
+ .new "#{ model_name } class doesn't include the Uuids::Base module"
86
+ end
87
+
88
+ def check_column
89
+ return if klass.attribute_names.include? column_name
90
+ fail NotImplementedError
91
+ .new "#{ class_name }##{ column_name } attribute isn't implemented"
92
+ end
93
+
94
+ def add_getter
95
+ klass.class_eval getter
96
+ end
97
+
98
+ def add_setter
99
+ klass.class_eval setter
100
+ end
101
+
102
+ def getter
103
+ "def #{ name };
104
+ uuid = read_attribute :#{ column_name };
105
+ return @#{ name } = nil unless uuid;
106
+ if Array(@#{ name }.try(:uuids)).map(&:value).include? uuid;
107
+ @#{ name };
108
+ else;
109
+ @#{ name } = #{ model_name }.by_uuid(uuid).includes(:uuids).first;
110
+ end;
111
+ end"
112
+ end
113
+
114
+ def setter
115
+ "def #{ name }=(value);
116
+ fail TypeError unless value.nil? || value.is_a?(#{ model_name });
117
+ write_attribute :#{ column_name }, value.try(:uuid);
118
+ #{ name };
119
+ end"
120
+ end
121
+ end
122
+ end
123
+ end
@@ -1,13 +1,16 @@
1
1
  module Uuids
2
2
  module Base
3
3
 
4
+ # @api hide
4
5
  # Defines methods to be added by the +has_uuids+ class helper.
5
6
  module HasUuids
6
7
  extend ActiveSupport::Concern
7
8
 
9
+ # @api hide
8
10
  # Model scopes.
9
11
  module ClassMethods
10
12
 
13
+ # @api hide
11
14
  # Selects records by uuid(s).
12
15
  #
13
16
  # @example Selects records by a list of uuids
@@ -32,8 +35,22 @@ module Uuids
32
35
  def by_uuid(*values)
33
36
  Queries::ByUuid.select(self, *values)
34
37
  end
38
+
39
+ private
40
+
41
+ # @api hide
42
+ # Associates uuids to the current model.
43
+ def has_many_uuids
44
+ has_many(
45
+ :uuids,
46
+ class_name: "Uuids::Models::Uuid",
47
+ as: :record,
48
+ validate: false
49
+ )
50
+ end
35
51
  end
36
52
 
53
+ # @api hide
37
54
  # Returns the first UUID (sorted as a string) for the record.
38
55
  #
39
56
  # @example
@@ -46,6 +63,7 @@ module Uuids
46
63
  uuids.map(&:value).sort.first
47
64
  end
48
65
 
66
+ # @api hide
49
67
  # Assigns a new uuid to the record.
50
68
  #
51
69
  # @example
@@ -58,6 +76,7 @@ module Uuids
58
76
  uuids.new value: value
59
77
  end
60
78
 
79
+ # @api hide
61
80
  # Assigns a list of new uuids to the record.
62
81
  #
63
82
  # @example
data/lib/uuids/base.rb CHANGED
@@ -21,6 +21,8 @@ module Uuids
21
21
  #
22
22
  # @example
23
23
  # class City < ActiveRecord::Base
24
+ # include Uuids::Base
25
+ #
24
26
  # has_uuids
25
27
  # end
26
28
  #
@@ -43,21 +45,38 @@ module Uuids
43
45
  # # => true
44
46
  def has_uuids
45
47
  include Uuids::Base::HasUuids
46
- add_association
48
+ has_many_uuids
47
49
  after_initialize :add_default_uuid
48
50
  before_destroy :prevent_destruction
49
51
  validates :uuids, presence: true, on: :update
50
52
  end
51
53
 
52
- # @api hide
53
- # Associates uuids to the current model.
54
- def add_association
55
- has_many(
56
- :uuids,
57
- class_name: "Uuids::Models::Uuid",
58
- as: :record,
59
- validate: false
60
- )
54
+ # The helper defines both the getter and setter for object, associated
55
+ # by uuid.
56
+ #
57
+ # @example
58
+ # class City < ActiveRecord::Base
59
+ # include Uuids::Base
60
+ #
61
+ # belongs_by_uuid_to :state, class: State
62
+ # end
63
+ #
64
+ # city = City.new
65
+ # city.state_uuid = "12345678-90ab-cdef-1234-567890abcdef"
66
+ #
67
+ # city.state.class # => State
68
+ # city.state.uuid # => "12345678-90ab-cdef-1234-567890abcdef"
69
+ #
70
+ # city.state = State.new uuid: "fedcba98-7654-3210-fedc-ba9876543210"
71
+ # city.state.uuid # => "fedcba98-7654-3210-fedc-ba9876543210"
72
+ #
73
+ # @param [String, Symbol] name The name of the attribute.
74
+ # @param [Hash] options The options for the association.
75
+ # @option options [Class] :class The model of the attribute.
76
+ # @option options [String] :class_name The name of the attribute's model.
77
+ def belongs_by_uuid_to(name, options = {})
78
+ class_name = options[:class] || options[:class_name].constantize
79
+ BelongsTo.add self, name, class_name
61
80
  end
62
81
  end
63
82
 
data/lib/uuids/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Uuids
2
2
 
3
3
  # Current release.
4
- VERSION = "4.0.1"
4
+ VERSION = "4.1.0"
5
5
  end
@@ -0,0 +1,6 @@
1
+ require "uuids"
2
+
3
+ class State < ActiveRecord::Base
4
+ include Uuids::Base
5
+ has_uuids
6
+ end
@@ -0,0 +1,8 @@
1
+ class CreateStates < ActiveRecord::Migration
2
+ def change
3
+ create_table :states do |t|
4
+
5
+ t.timestamps
6
+ end
7
+ end
8
+ end
@@ -1,7 +1,7 @@
1
1
  class CreateCities < ActiveRecord::Migration
2
2
  def change
3
3
  create_table :cities do |t|
4
-
4
+ t.string :state_uuid, limit: 36
5
5
  t.timestamps
6
6
  end
7
7
  end
@@ -11,9 +11,10 @@
11
11
  #
12
12
  # It's strongly recommended that you check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(version: 20141017081115) do
14
+ ActiveRecord::Schema.define(version: 20151215182355) do
15
15
 
16
16
  create_table "cities", force: true do |t|
17
+ t.string "state_uuid", limit: 36
17
18
  t.datetime "created_at"
18
19
  t.datetime "updated_at"
19
20
  end
@@ -23,6 +24,11 @@ ActiveRecord::Schema.define(version: 20141017081115) do
23
24
  t.datetime "updated_at"
24
25
  end
25
26
 
27
+ create_table "states", force: true do |t|
28
+ t.datetime "created_at"
29
+ t.datetime "updated_at"
30
+ end
31
+
26
32
  create_table "uuids_uuids", force: true do |t|
27
33
  t.string "value", limit: 36, null: false
28
34
  t.integer "record_id", null: false
Binary file
@@ -81,5 +81,70 @@ module Uuids
81
81
  expect { subject.destroy! }.not_to raise_error
82
82
  end
83
83
  end
84
+
85
+ describe ".belongs_by_uuid_to" do
86
+
87
+ context "when a model doesn't include Uuids::Base" do
88
+
89
+ it "raises TypeError" do
90
+ expect { City.send :belongs_by_uuid_to, :state, class: Record }
91
+ .to raise_error { TypeError }
92
+ end
93
+ end
94
+
95
+ context "when a class doesn't have column for uuids" do
96
+
97
+ it "raises NotImplementedError" do
98
+ expect { City.send :belongs_by_uuid_to, :country, class: State }
99
+ .to raise_error { NotImplementedError }
100
+ end
101
+ end
102
+
103
+ context "with valid arguments" do
104
+
105
+ before { City.send :belongs_by_uuid_to, :state, class: State }
106
+ subject { City.new }
107
+
108
+ let!(:uuid) { "01234567-89ab-cdef-0123-456789abcdef" }
109
+ let!(:state) { State.create uuid: uuid }
110
+
111
+ it "defines the getter" do
112
+ expect(subject).to respond_to :state
113
+ expect(subject.method(:state).arity).to eq 0
114
+ end
115
+
116
+ it "defines the setter" do
117
+ expect(subject).to respond_to :state=
118
+ expect(subject.method(:state=).arity).to eq 1
119
+ end
120
+
121
+ it "sets the object" do
122
+ expect { subject.state = state }
123
+ .to change { subject.state }.to state
124
+ end
125
+
126
+ it "sets the object uuid" do
127
+ expect { subject.state = state }
128
+ .to change { subject.state_uuid }.to state.uuid
129
+ end
130
+
131
+ it "resets the object" do
132
+ subject.state = state
133
+ expect { subject.state = nil }
134
+ .to change { subject.state }.to nil
135
+ end
136
+
137
+ it "resets the object uuid" do
138
+ subject.state = state
139
+ expect { subject.state = nil }
140
+ .to change { subject.state_uuid }.to nil
141
+ end
142
+
143
+ it "sets the object by uuid" do
144
+ expect { subject.state_uuid = state.uuid }
145
+ .to change { subject.state }.to state
146
+ end
147
+ end
148
+ end
84
149
  end
85
150
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uuids
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.1
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kozin
@@ -218,19 +218,22 @@ files:
218
218
  - db/migrate/20141016112506_create_uuids_uuids.rb
219
219
  - lib/uuids.rb
220
220
  - lib/uuids/base.rb
221
+ - lib/uuids/base/belongs_to.rb
221
222
  - lib/uuids/base/has_uuids.rb
222
223
  - lib/uuids/version.rb
223
224
  - spec/bin/uuids_spec.rb
224
225
  - spec/dummy/Rakefile
225
226
  - spec/dummy/app/models/city.rb
226
227
  - spec/dummy/app/models/record.rb
228
+ - spec/dummy/app/models/state.rb
227
229
  - spec/dummy/config/database.yml
228
230
  - spec/dummy/config/environment.rb
229
231
  - spec/dummy/config/initializers/application.rb
230
232
  - spec/dummy/config/initializers/dummy.rb
231
233
  - spec/dummy/config/initializers/seed_loader.rb
232
234
  - spec/dummy/db/migrate/20141016113016_create_records.rb
233
- - spec/dummy/db/migrate/20141017081115_create_cities.rb
235
+ - spec/dummy/db/migrate/20141215182349_create_states.rb
236
+ - spec/dummy/db/migrate/20151215182355_create_cities.rb
234
237
  - spec/dummy/db/schema.rb
235
238
  - spec/dummy/db/test.sqlite3
236
239
  - spec/dummy/lib/dummy.rb
@@ -288,10 +291,12 @@ test_files:
288
291
  - spec/dummy/config/initializers/seed_loader.rb
289
292
  - spec/dummy/config/initializers/application.rb
290
293
  - spec/dummy/config/initializers/dummy.rb
291
- - spec/dummy/db/migrate/20141017081115_create_cities.rb
294
+ - spec/dummy/db/migrate/20141215182349_create_states.rb
292
295
  - spec/dummy/db/migrate/20141016113016_create_records.rb
296
+ - spec/dummy/db/migrate/20151215182355_create_cities.rb
293
297
  - spec/dummy/db/test.sqlite3
294
298
  - spec/dummy/db/schema.rb
299
+ - spec/dummy/app/models/state.rb
295
300
  - spec/dummy/app/models/record.rb
296
301
  - spec/dummy/app/models/city.rb
297
302
  - spec/dummy/lib/dummy.rb