uuids 0.2.0 → 1.0.0.pre.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5e74d457a60d98ff3a145f6a6a1833f2075983af
4
- data.tar.gz: 6ff0c0939c243ef4648edb145a5d6f5b3b9cab3b
3
+ metadata.gz: 716ef7b1e74c7adf9fd9d29302aa0ad0b2ba6c74
4
+ data.tar.gz: 6086c3c5ece7db6730ef17aa814373789ea03189
5
5
  SHA512:
6
- metadata.gz: 8d4b2414ae87ce041c34248cb76c4e382072d2e20f5e1b54c86a884b5cb488bc703acf02220a8012fb8f3bb080dac55801a779147c67cd73567375ee182016fa
7
- data.tar.gz: 168e82b3e79766a35e814ccb6660f35d4a82d277a8a9a23030936099faa4aa4c631a748beceadb5f72766dd1293b2c50662f2f9b4729106634faf645aabd8499
6
+ metadata.gz: bc6c1947993bddd20aae7128f7be6987032bb7018e073a48c841a69ba4208ffdb20b854c2dec71d583a6f95b76ca2b35e944b7567e1050a2210a7946e8cf04af
7
+ data.tar.gz: 9a663e80d1b08d164eeb9a3ecab76fb5bf3d1051cecb579360bbae7333bf710fa87169d477f829133761012d4694c0665d5bbe555389dec0d9cacc57e3f8e43a
data/.rubocop.yml CHANGED
@@ -11,6 +11,10 @@ Lint/RescueException:
11
11
  Exclude:
12
12
  - 'spec/**/*'
13
13
 
14
+ Metrics/MethodLength:
15
+ Exclude:
16
+ - 'db/**/*'
17
+
14
18
  Style/AccessorMethodName:
15
19
  Exclude:
16
20
  - 'spec/**/*'
@@ -31,9 +35,8 @@ Style/EmptyLineBetweenDefs:
31
35
  Exclude:
32
36
  - 'spec/**/*'
33
37
 
34
- Metrics/MethodLength:
35
- Exclude:
36
- - 'db/**/*'
38
+ Style/PredicateName:
39
+ Enabled: false
37
40
 
38
41
  Style/RaiseArgs:
39
42
  EnforcedStyle: compact
data/README.rdoc CHANGED
@@ -9,53 +9,44 @@
9
9
 
10
10
  == About
11
11
 
12
- Defines a model +Uuid+ to store {UUIDs}[http://en.wikipedia.org/wiki/Universally_Unique_Identifier] assigned to various AR records.
12
+ The gem adds addressing ActiveRecord objects by {UUID}[http://en.wikipedia.org/wiki/Universally_Unique_Identifier]s following the {RFC4122}[http://www.ietf.org/rfc/rfc4122.txt]
13
+ standard.
13
14
 
14
- It is expected any uuid is assigned to one record, but a record can be
15
- identified by many uuids.
16
-
17
- The gem is a {mountable Rails engine}[http://guides.rubyonrails.org/engines.html#generating-an-engine].
18
-
19
- The gem provides:
15
+ It provides:
20
16
 
21
17
  <tt>Uuids::Uuid</tt>:: A model of UUIDs associated with various records.
22
- <tt>Uuids::Base</tt>:: A module to be included to AR model to provide required +#uuids+ attribute.
18
+ <tt>Uuids::Base</tt>:: A module provides ActiveRecord class helpers +has_uuids+ and +has_many+ (with <tt>uuid: true</tt> option).
19
+
20
+ The gem is a {mountable Rails engine}[http://guides.rubyonrails.org/engines.html#generating-an-engine].
23
21
 
24
22
  === Pattern
25
23
 
26
- This model allows refering records by some uuid (not the id).
24
+ This model allows adressing records by some UUID (not the ID).
25
+ It is expected any UUID is assigned to one record, but a record can be
26
+ identified by many UUIDs.
27
27
 
28
28
  If necessary any referred record can be merged with another one.
29
- If you reassign all their uuids to merged record then any references remains
30
- valid without tracking and changing them before merge.
31
-
32
- A uuid should be neither deleted, no changed. It can only be reassigned to
33
- another resource. The records can be deleted
29
+ All you need is to reassign all UUIDs to merged record and outer associations
30
+ remains valid.
34
31
 
35
- * by merging to another ones;
36
- * by explicitly marking as deleted without physical removal.
32
+ A **UUID** should be neither deleted, no changed. It can only be reassigned to
33
+ another resource. On ther other hand, the outer record should be merged to
34
+ another one (reassign UUIDs) to prevent existance of UUIDs assigned to nothing.
37
35
 
38
36
  === Example
39
37
 
40
38
  Suppose you have models referred to cities. One day you discover
41
- a duplication among cities: the "New York" and the "NEW YORK".
39
+ a duplication among two cities: the "New York" and the "NEW YORK".
42
40
 
43
41
  You should:
44
42
 
45
- * reassign both uuids to "New York";
43
+ * reassign both UUIDs to "New York";
46
44
  * safely remove the "NEW YORK" record.
47
45
 
48
46
  You needn't track all records that refer to "NEW YORK". All those references
49
- will authomatically lead to merged record via old uuid.
50
-
51
- === Standards
47
+ will authomatically lead to merged record via old UUID.
52
48
 
53
- The Uuid is generated authomatically following the
54
- {RFC4122}[http://www.ietf.org/rfc/rfc4122.txt] standard. The generation uses the
55
- +sequrerandom+ Ruby library.
56
-
57
- This allows keeping all uuids in one model and referring to any record whatever
58
- type it has.
49
+ Now the model of cities should **know nothing about outer models** that use it.
59
50
 
60
51
  === Translations
61
52
 
@@ -76,90 +67,101 @@ Or install it yourself as:
76
67
 
77
68
  $ gem install uuids
78
69
 
70
+ == Initialization
71
+
72
+ To initialize the module you need to copy and run uuid's db migrations.
73
+
79
74
  === Rails application
80
75
 
81
76
  Run from a command line in application root:
82
77
 
83
78
  $ rake uuids:install
84
79
 
85
- This will copy gem migrations to a `db/migrate` folder and run it.
86
-
87
80
  === Rails mountable engine
88
81
 
89
82
  Run from a command line in application root:
90
83
 
91
84
  $ rake app:uuids:install
92
85
 
93
- This will copy gem migrations to a `spec/dummy/db/migrate` folder and run it.
94
-
95
86
  == Usage
96
87
 
88
+ === Adding UUIDs identifiers
89
+
97
90
  Add the assotiation to your AR model:
98
91
 
99
- class YourModel < ActiveRecord::Base
92
+ class City < ActiveRecord::Base
93
+ include Uuids::Base
94
+ has_uuids
95
+ end
100
96
 
101
- # declares the association
102
- has_many :uuids, class_name: "Uuids::Uuid", as: :record, validate: false
97
+ This will add methods:
103
98
 
104
- # auto-generates uuid by default
105
- before_create -> { uuids.present? || uuids.new }
99
+ +#uuids+:: List of <tt>Uuids::Uuid</tt> objects referred to the record.
100
+ +#uuid+:: main UUID for the record - a value of the first +uuids+ object.
101
+ <tt>.by_uuid</tt>:: A scope for unique records by UUID: <tt>City.by_uuid</tt>
106
102
 
107
- # prevents the record from being unreferable
108
- validates :uuids, presence: true, on: :update
103
+ The first uuid is added by default. It can also be set manually:
104
+
105
+ # UUID is generated by default
106
+ city = City.new
107
+ city.save!
109
108
 
110
- # prevents a record destruction before its uuids reassigned to another one
111
- before_destroy -> { uuids.blank? }
112
- end
109
+ # UUID is assigned manually
110
+ city = City.new
111
+ city.uuids.new value: "6d9456a9-8f54-4ff7-ba0d-9854f1954417"
112
+ city.save
113
113
 
114
- Instead of above you can simply include the Uuids::Base module:
114
+ The destruction of object is forbidden if it has a +uuid+. You should reassign
115
+ all object's UUIDs to another object in advance.
115
116
 
116
- class YourModel < ActiveRecord::Base
117
- include Uuids::Base
118
- end
117
+ === Referring model by UUID [TODO]
119
118
 
120
- Now you can refer to your model via uuid:
119
+ Instead of <tt>ActiveRecord::Associations</tt> +belongs_to+, +has_one+ and
120
+ +has_many+, you should define custom methods by <tt>ActiveRecord::Relation</tt>
121
+ explicitly.
121
122
 
122
- class CreateAnotherModelTable < ActiveRecord::Migration
123
+ class CreateStreetsTable < ActiveRecord::Migration
123
124
  def change
124
- create_table :another_models do |t|
125
- t.string :your_model_uuid, limit: 36
125
+ create_table :streets do |t|
126
+ t.string :city_uuid, limit: 36
126
127
  end
127
- add_index :another_models, :your_model_uuid
128
+ add_index :streets_table, :city_uuid
128
129
  end
129
130
  end
130
131
 
131
- class AnotherModel < ActiveRecord::Base
132
+ class Street < ActiveRecord::Base
132
133
 
133
- def your_model
134
- @your_model ||= YourModel.join(:uuids)
135
- .where(uuids_uuids: { value: your_model_uuid }).first
134
+ scope :by_city, ->(city) { City.by_uuid(city.uuid) }
135
+
136
+ def city
137
+ @city ||= City.by_uuid(city_uuid)
136
138
  end
137
139
 
138
- def your_model=(record)
139
- @your_model_uuid ||= Uuids::Uuid.find_by_record(record).try(:value)
140
+ def city=(city)
141
+ read_attribute :city_uuid, city.uuid
140
142
  end
141
143
  end
142
144
 
143
145
  == Uninstallation
144
146
 
147
+ To uninstall the module you need to:
148
+
149
+ * rollback and remove uuid's migration;
150
+ * remove all lines containing <tt>include Uuids::Base</tt>, +has_uuids+ and <tt>by_uuid: true</tt> from any model;
151
+ * remove the gem dependencies from application's +Gemfile+ and gemspec.
152
+
145
153
  === Rails app
146
154
 
147
155
  Run from a command line in application root:
148
156
 
149
157
  $ rake uuids:uninstall
150
158
 
151
- This will rollback and remove migration from `db/migrate` folder and then
152
- remove the gem dependencies from application's +Gemfile+ and gemspec.
153
-
154
159
  === Rails mountable engine
155
160
 
156
161
  Run from a command line in engine root:
157
162
 
158
163
  $ rake app:uuids:uninstall
159
164
 
160
- This will rollback and remove migration from `spec/dummy/db/migrate` folder and
161
- then remove the gem dependencies from engine's +Gemfile+ and gemspec.
162
-
163
165
  == Contributing
164
166
 
165
167
  1. Fork it ( https://github.com/nepalez/uuids/fork )
@@ -168,17 +170,6 @@ then remove the gem dependencies from engine's +Gemfile+ and gemspec.
168
170
  4. Push to the branch (`git push origin my-new-feature`)
169
171
  5. Create a new Pull Request
170
172
 
171
- == TODO
172
-
173
- Redefine AR::Base class methods +has_one+ and +has_many+ to allow reference
174
- by uuid:
175
-
176
- class MyModel < ActiveRecord::Base
177
- include Uuids::Associations
178
-
179
- has_one :another_model, uuid: true
180
- end
181
-
182
173
  == License
183
174
 
184
175
  The plugin is distributed under {MIT license}[https://github.com/nepalez/uuids/blob/master/LICENSE.rdoc]
@@ -14,18 +14,17 @@ namespace :uuids do
14
14
 
15
15
  def remove_gem
16
16
  say "Removing the 'uuids' gem" do
17
- remove_from_file "Gemfile", /gem\s+["|']uuids["|']/
18
- Dir["*.gemspec"].each do |gemspec|
19
- remove_from_file gemspec, /_dependency\s+["|']uuids["|']/
20
- end
17
+ GEMFILE = /gem\s+["|']uuids["|']/
18
+ GEMSPEC = /_dependency\s+["|']uuids["|']/
19
+ remove_from_file "Gemfile", GEMFILE
20
+ Dir["*.gemspec"].each { |file| remove_from_file file, GEMSPEC }
21
21
  end
22
22
  end
23
23
 
24
24
  def remove_from_file(name, regex)
25
25
  say_with_time name do
26
- temp = File.read(name).split("\n")
27
- .reject { |line| line[regex] }.join("\n")
28
- File.write(name, temp)
26
+ temp = File.read(name).split("\n").reject { |line| line[regex] }.join "\n"
27
+ File.write name, temp
29
28
  end
30
29
  end
31
30
 
data/lib/uuids/base.rb CHANGED
@@ -2,25 +2,61 @@ module Uuids
2
2
 
3
3
  # Creates required `#uuids` attribute of the ActiveRecord model.
4
4
  module Base
5
+ extend ActiveSupport::Concern
5
6
 
7
+ # Prevents the module usage outside an ActiveRecord model.
8
+ #
9
+ # class Text < String
10
+ # include Uuids::Base
11
+ # end
12
+ # # => raises a TypeError
13
+ #
6
14
  def self.included(klass)
7
- fail unless klass.ancestors.include? ActiveRecord::Base
15
+ unless klass.ancestors.include? ActiveRecord::Base
16
+ fail TypeError.new("#{ klass.name } isn't an ActiveRecord model.")
17
+ end
18
+ end
8
19
 
9
- klass.has_many :uuids, uuids_params
20
+ # Methods added to the ActiveRecord model.
21
+ module ClassMethods
10
22
 
11
- klass.before_create :add_default_uuid
12
- klass.before_destroy :prevent_destruction
23
+ private
13
24
 
14
- klass.validates :uuids, presence: true, on: :update
15
- end
25
+ # Declares:
26
+ #
27
+ # * +uuids+ association attribute;
28
+ # * +uuid+ method (string);
29
+ # * <tt>uuid</tt> relation scope.
30
+ #
31
+ def has_uuids
32
+ define_uuids
33
+ define_uuid_getter
34
+ define_scope
35
+ end
16
36
 
17
- private
37
+ # Defines the +uuids+ association attribute;
38
+ def define_uuids
39
+ has_many :uuids, class_name: "Uuids::Uuid", as: :record, validate: false
40
+ before_create :add_default_uuid
41
+ before_destroy :prevent_destruction
42
+ validates :uuids, presence: true, on: :update
43
+ end
18
44
 
19
- # Parameters for uuid associations
20
- def self.uuids_params
21
- { class_name: "Uuids::Uuid", as: :record, validate: false }
45
+ # Defines the +uuid+ method
46
+ def define_uuid_getter
47
+ class_eval "def uuid; uuids.first.try(:value); end"
48
+ end
49
+
50
+ # Defines the <tt>uuid</tt> relation scope.
51
+ def define_scope
52
+ scope :by_uuid, ->(value) {
53
+ joins(:uuids).where(uuids_uuids: { value: value }).uniq
54
+ }
55
+ end
22
56
  end
23
57
 
58
+ private
59
+
24
60
  # Creates the uuids by default preventing a record from being ureferrable
25
61
  def add_default_uuid
26
62
  uuids.present? || uuids.new
data/lib/uuids/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  module Uuids
3
3
 
4
4
  # Current release.
5
- VERSION = "0.2.0"
5
+ VERSION = "1.0.0-rc1"
6
6
  end
@@ -0,0 +1,5 @@
1
+ require "uuids"
2
+
3
+ class City < ActiveRecord::Base
4
+ include Uuids::Base
5
+ end
@@ -0,0 +1,8 @@
1
+ class CreateCities < ActiveRecord::Migration
2
+ def change
3
+ create_table :cities do |t|
4
+
5
+ t.timestamps
6
+ end
7
+ end
8
+ end
@@ -13,7 +13,7 @@
13
13
 
14
14
  ActiveRecord::Schema.define(version: 20141017081115) do
15
15
 
16
- create_table "items", force: true do |t|
16
+ create_table "cities", force: true do |t|
17
17
  t.datetime "created_at"
18
18
  t.datetime "updated_at"
19
19
  end
Binary file