active-record-binder 1.1.0 → 1.2.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.
Files changed (47) hide show
  1. data/README.md +217 -0
  2. data/bin/arb +13 -0
  3. data/doc/Binder.html +150 -0
  4. data/doc/Binder/AR.html +1880 -0
  5. data/doc/Binder/Command.html +252 -0
  6. data/doc/Binder/Help.html +374 -0
  7. data/doc/Binder/Migrate.html +682 -0
  8. data/doc/Binder/Strategy.html +550 -0
  9. data/doc/Binder/Version.html +285 -0
  10. data/doc/Class.html +220 -0
  11. data/doc/CommandParser.html +268 -0
  12. data/doc/CommandParser/ParseError.html +123 -0
  13. data/doc/DeferedDelegator.html +414 -0
  14. data/doc/MigrationProcessError.html +123 -0
  15. data/doc/MigrationVersionError.html +123 -0
  16. data/doc/String.html +245 -0
  17. data/doc/_index.html +256 -0
  18. data/doc/class_list.html +53 -0
  19. data/doc/css/common.css +1 -0
  20. data/doc/css/full_list.css +57 -0
  21. data/doc/css/style.css +328 -0
  22. data/doc/file.README.html +300 -0
  23. data/doc/file_list.html +55 -0
  24. data/doc/frames.html +28 -0
  25. data/doc/index.html +300 -0
  26. data/doc/js/app.js +214 -0
  27. data/doc/js/full_list.js +173 -0
  28. data/doc/js/jquery.js +4 -0
  29. data/doc/method_list.html +348 -0
  30. data/doc/top-level-namespace.html +114 -0
  31. data/extras/cli_help.png +0 -0
  32. data/lib/active_record_binder.rb +21 -37
  33. data/lib/cli/command.rb +101 -0
  34. data/lib/cli/command_parser.rb +29 -0
  35. data/lib/cli/commands/commands.rb +4 -0
  36. data/lib/cli/commands/help.rb +35 -0
  37. data/lib/cli/commands/migrate.rb +77 -0
  38. data/lib/cli/commands/version.rb +16 -0
  39. data/lib/cli/core_ext.rb +21 -0
  40. data/lib/defered_delegator.rb +69 -0
  41. data/lib/version.rb +3 -0
  42. data/test/active_record_binder_test.rb +262 -0
  43. data/test/foo.sqlite3 +0 -0
  44. data/test/migrations.rb +29 -0
  45. data/test/minitest_helper.rb +15 -0
  46. data/test/mocks.rb +24 -0
  47. metadata +62 -5
@@ -0,0 +1,16 @@
1
+ require 'version'
2
+
3
+ module Binder
4
+ # Public: [Command] Displays the current ARB version. Used via the `arb` command.
5
+ class Version < Binder::Strategy
6
+ def execute args
7
+ "Binder::AR::Version => #{Binder::VERSION}".colorize(:orange)
8
+ end
9
+
10
+ def description
11
+ "Displays Binder::AR's gem current version"
12
+ end
13
+
14
+ alias_class :V
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ class Class
2
+ # Public: Handy ! Returns all subclasses of a specific class.
3
+ #
4
+ # Returns an Array of Classes.
5
+ def subclasses
6
+ ObjectSpace.each_object(Class).select { |klass| klass < self }
7
+ end
8
+ end
9
+
10
+ class String
11
+ # Public: Colorize a string for a Unix terminal.
12
+ #
13
+ # code - The color code: a Numeric [0-255] or a Symbol [:red, :green, :orange, :purple, :rose].
14
+ #
15
+ # Returns a colorized string.
16
+ def colorize code
17
+ colors = { red: 31, green: 32, orange: 33, purple: 34, rose: 35 }
18
+ code = colors[code] unless code.kind_of? Numeric
19
+ "\e[#{code}m#{self}\e[0m"
20
+ end
21
+ end
@@ -0,0 +1,69 @@
1
+ # Private: A simple module that delegates classes methods when needed, keeping the calls in memory.
2
+ #
3
+ # Examples
4
+ #
5
+ # class Foo
6
+ # def self.foo arg
7
+ # "World of #{arg}"
8
+ # end
9
+ # #
10
+ # def self.bar
11
+ # "Hello"
12
+ # end
13
+ # end
14
+ #
15
+ # class Baz
16
+ # extend DeferedDelegator
17
+ # register_delegators :bar, :foo
18
+ # #
19
+ # def initialize obj
20
+ # @obj = obj
21
+ # end
22
+ # #
23
+ # def foobar
24
+ # delegate_to @obj
25
+ # end
26
+ # end
27
+ #
28
+ # class Bar < Baz
29
+ # foo "Foo"
30
+ # bar
31
+ # end
32
+ #
33
+ # Bar.new Foo
34
+ # Bar.foobar
35
+ # # => "World of Foo"
36
+ # # => "Hello"
37
+ module DeferedDelegator
38
+ # Public: Allows to register delegators
39
+ #
40
+ # args - List of Symbols, the method name that will be delegated.
41
+ #
42
+ # Returns Nothing.
43
+ def register_delegators *args
44
+ args.each do |delegator|
45
+ delegator = delegator.to_s
46
+ module_eval %Q{
47
+ def self.#{delegator} *parameters
48
+ @delegators ||= []
49
+ @delegators << { name: :#{delegator}, params: parameters }
50
+ end
51
+ }
52
+ end
53
+ end
54
+
55
+ # Public: Triggers the delegation and run the delegated methods
56
+ #
57
+ # klass_or_object - A Class or an Object to delegate to.
58
+ #
59
+ # Returns Nothing.
60
+ def delegate_to klass_or_object
61
+ @delegators.each do |data|
62
+ unless data.empty?
63
+ name = data[:name]
64
+ args = data[:params]
65
+ klass_or_object.send(name, *args)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,3 @@
1
+ module Binder
2
+ VERSION = "1.2.0"
3
+ end
@@ -0,0 +1,262 @@
1
+ require_relative 'minitest_helper'
2
+ require_relative '../lib/active_record_binder'
3
+ require_relative './mocks'
4
+ require_relative './migrations'
5
+
6
+ describe Binder::AR do
7
+ describe 'Database information' do
8
+ context 'default' do
9
+ it 'should have a sensible default to an ENV variable' do
10
+ ENV['APP_DB'] = 'Foo'
11
+ Binder::AR.default_database.must_equal ENV['APP_DB']
12
+ end
13
+ end # default
14
+
15
+ context 'specified' do
16
+ it 'should have a way to set a database' do
17
+ Binder::AR.database 'Foobar'
18
+ Binder::AR.database.must_equal 'Foobar'
19
+ end
20
+ it 'should switch to default if nothing is specified' do
21
+ Binder::AR.database nil
22
+ Binder::AR.database.must_equal Binder::AR.default_database
23
+ end
24
+ context 'each subclass' do
25
+ it 'should have different settings from another' do
26
+ MockBond.database 'Bar'
27
+ OtherMockBond.database 'Baz'
28
+ MockBond.database.must_equal 'Bar'
29
+ OtherMockBond.database.must_equal 'Baz'
30
+ end
31
+ end
32
+ end # Specified
33
+ end # Database
34
+
35
+ describe 'Connection adapter' do
36
+ context 'default' do
37
+ it 'should use sqlite as a default adapter' do
38
+ Binder::AR.default_adapter.must_equal :sqlite3
39
+ end
40
+ end
41
+ context 'specified' do
42
+ it 'should give a way to set a specific adapter' do
43
+ Binder::AR.adapter :mysql2
44
+ Binder::AR.adapter.must_equal :mysql2
45
+ end
46
+ it 'should use sqlite if nothing is specified' do
47
+ Binder::AR.adapter nil
48
+ Binder::AR.adapter.must_equal Binder::AR.default_adapter
49
+ end
50
+ context 'each subclass' do
51
+ it 'should have different settings from another' do
52
+ MockBond.adapter 'Bar'
53
+ OtherMockBond.adapter 'Baz'
54
+ MockBond.adapter.must_equal 'Bar'
55
+ OtherMockBond.adapter.must_equal 'Baz'
56
+ end
57
+ end
58
+ end # specified
59
+ end # Connection adapter
60
+
61
+ describe 'Connection params' do
62
+ it 'should give a way to set connection parameters' do
63
+ params = { user: 'Poney', password: 'Poney234' }
64
+ Binder::AR.connect_with params
65
+ Binder::AR.connect_with.must_equal params
66
+ end
67
+ end
68
+
69
+ describe 'Binder Object' do
70
+ let(:binder) { MockBond.new :foo }
71
+ it 'On instanciation, should automaticaly create an AR Record object matching the table name and namespaced under the current binder class' do
72
+ binder.table.must_equal binder.class::Foo
73
+ end
74
+ end # Connection parms
75
+
76
+ describe 'AR Bound Object' do
77
+ let(:model) { MockBond.new(:foo).table }
78
+
79
+ it 'should be an instance of a subclass ActiveRecord::Base' do
80
+ model.superclass.must_equal ActiveRecord::Base
81
+ end
82
+
83
+ describe 'connection' do
84
+ it 'should respond to connect' do
85
+ model.must_respond_to :connect
86
+ end
87
+ it 'should respond to connected?' do
88
+ model.must_respond_to :connected?
89
+ end
90
+ it 'should be connected automaticaly on instanciation' do
91
+ # Should be replace with something else, but it activates the connection so it's pretty easy
92
+ model.first
93
+ model.connected?.must_equal true
94
+ end
95
+ end
96
+
97
+ describe 'ActiveRecord methods' do
98
+ it 'should respond to find' do
99
+ model.must_respond_to :find
100
+ end
101
+ it 'should respond to first' do
102
+ model.must_respond_to :first
103
+ end
104
+ it 'should respond to all' do
105
+ model.must_respond_to :all
106
+ end
107
+ it 'should respond to delete' do
108
+ model.must_respond_to :delete
109
+ end
110
+ it 'should respond to update_attributes' do
111
+ model.first.must_respond_to :update_attributes
112
+ end
113
+ it 'should respond to save' do
114
+ model.new.must_respond_to :save
115
+ end
116
+ end
117
+
118
+ describe 'ActiveRecord relations' do
119
+ it 'should handle one to one relationships' do
120
+ model.has_one :article
121
+ model.first.article.must_equal Article.first
122
+ end
123
+
124
+ # As it's active record, it should work with other associations types too.
125
+ # TODO: Test other associations
126
+ end
127
+ end # Ar Bound Object
128
+
129
+ describe 'Migration system' do
130
+ context 'schema definition' do
131
+ let(:migration) { FooCreateTable }
132
+
133
+ it 'should have a Version method' do
134
+ Binder::AR.must_respond_to :Version
135
+ end
136
+
137
+ it 'inheriting through the Version method should create a subclass of ActiveRecord::Migration' do
138
+ migration.superclass.superclass.must_equal ActiveRecord::Migration
139
+ end
140
+
141
+ context 'Versionning' do
142
+ it "should have a version method, that returns this migration's version" do
143
+ migration.version.must_equal 1.0
144
+ end
145
+ end
146
+ end # schema definition
147
+
148
+ context 'migration' do
149
+ it 'should have a migrate method' do
150
+ Binder::AR.must_respond_to :migrate
151
+ MockBond.must_respond_to :migrate
152
+ end
153
+
154
+ it 'should create a schema containing the metadata for the migration system, namespaced inside the binder' do
155
+ # Reset migrations
156
+ MockBond.migrate 0
157
+ MockBond.migrate
158
+ MockBond::MetaSchema.must_be_kind_of Object
159
+ end
160
+
161
+ it 'can take a version number as an argument and return the executed-down-to migration number' do
162
+ MockBond.migrate(1.0).must_equal 1.0
163
+ end
164
+
165
+ it 'should fail if the migration version specified does not exist' do
166
+ ->{ MockBond.migrate(10.0) }.must_raise MigrationVersionError
167
+ end
168
+
169
+ describe 'migrate up and down' do
170
+ before do
171
+ # Make sure that we are at the first migration
172
+ MockBond.migrate 0
173
+ MockBond.migrate 1.0
174
+ @schema = MockBond.meta_schema
175
+ end
176
+
177
+ it 'should set the current migration to the desired number' do
178
+ MockBond.migrate 1.1
179
+ @schema.first.version.must_equal 1.1
180
+ end
181
+ it 'should make the change for the desired migration' do
182
+ MockBond.migrate 1.1
183
+ tags = MockBond.new(:tag).table
184
+ tags.create(name: 'foobar')
185
+ tags.first.name.must_equal "foobar"
186
+ end
187
+
188
+ describe 'version unspecified' do
189
+ it 'should migrate to the last version' do
190
+ MockBond.migrate
191
+ @schema.first.version.must_equal 1.1
192
+ end
193
+ end
194
+ end
195
+
196
+ context 'Schema MetaDatas' do
197
+ before do
198
+ MockBond.meta_schema
199
+ end
200
+
201
+ it 'should inherit from ActiveRecord::Base' do
202
+ MockBond::MetaSchema.superclass.must_equal ActiveRecord::Base
203
+ end
204
+
205
+ describe 'Meta schema' do
206
+ let(:meta_schema) { MockBond.meta_schema }
207
+
208
+ it 'should be accessible through the method schema_meta' do
209
+ meta_schema.must_equal MockBond::MetaSchema
210
+ end
211
+
212
+ it 'should create a metadata table namespaced under the binder class name' do
213
+ meta_schema.table_name.must_equal "mock_bond_meta_schemas"
214
+ end
215
+
216
+ its 'table should have a version column' do
217
+ meta_schema.new.must_respond_to :version
218
+ end
219
+ end # Describe Meta Schema
220
+ end # Context Schema Metadatas
221
+
222
+ end
223
+ end
224
+ end
225
+
226
+ class TestDelegators
227
+ extend DeferedDelegator
228
+ end
229
+
230
+ class TestDelegatedTo
231
+ def self.foo
232
+ @@test ||= []
233
+ @@test << true
234
+ end
235
+
236
+ def self.bar
237
+ @@test ||= []
238
+ @@test << false
239
+ end
240
+
241
+ def self.test
242
+ @@test
243
+ end
244
+ end
245
+
246
+ describe DeferedDelegator do
247
+ it 'provides a way to register delegators for a class' do
248
+ TestDelegators.register_delegators :foo
249
+ TestDelegators.must_respond_to :foo
250
+ end
251
+
252
+ it 'provides a way to call the delegation process and execute every registered delegation' do
253
+ TestDelegators.register_delegators :foo, :bar
254
+
255
+ TestDelegators.foo
256
+ TestDelegators.bar
257
+
258
+ TestDelegators.delegate_to TestDelegatedTo
259
+
260
+ TestDelegatedTo.test.must_equal [true, false]
261
+ end
262
+ end
Binary file
@@ -0,0 +1,29 @@
1
+ require_relative './mocks'
2
+ require_relative '../lib/active_record_binder'
3
+
4
+ class FooCreateTable < MockBond::Version 1.0
5
+ def self.up
6
+ create_table :tags do |t|
7
+ t.string :name
8
+ t.integer :tag_id, default: 0
9
+ t.timestamps
10
+ end
11
+ end
12
+
13
+ def self.down
14
+ drop_table :tags
15
+ end
16
+ end
17
+
18
+ class BarCreateTable < MockBond::Version 1.1
19
+ def self.up
20
+ create_table :foobz do |t|
21
+ t.string :foobar
22
+ t.timestamps
23
+ end
24
+ end
25
+
26
+ def self.down
27
+ drop_table :foobz
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ require 'minitest/spec'
2
+ require 'minitest/autorun'
3
+
4
+ require 'mocha/setup'
5
+
6
+ require 'turn/autorun'
7
+ Turn.config.format = :pretty
8
+
9
+ class MiniTest::Spec
10
+ class << self
11
+ alias :its :it
12
+ alias :they :it
13
+ alias :context :describe
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ require_relative '../lib/active_record_binder'
2
+
3
+ # Helper
4
+ class Class
5
+ def __DIR__
6
+ File.expand_path File.dirname(__FILE__)
7
+ end
8
+ end
9
+
10
+ class MockBond < Binder::AR
11
+ database __DIR__ + '/foo.sqlite3'
12
+ adapter :sqlite3
13
+
14
+ has_one :article
15
+ end
16
+
17
+ class OtherMockBond < Binder::AR
18
+ database :bar
19
+ adapter :sqlite3
20
+ end
21
+
22
+ # See test/foo.sqlite3
23
+ class Article < ActiveRecord::Base
24
+ end