active-record-binder 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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