clevic 0.8.0 → 0.11.1
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.
- data/History.txt +9 -0
- data/Manifest.txt +13 -10
- data/README.txt +6 -9
- data/Rakefile +35 -24
- data/TODO +29 -17
- data/bin/clevic +84 -37
- data/config/hoe.rb +7 -3
- data/lib/clevic.rb +2 -4
- data/lib/clevic/browser.rb +37 -49
- data/lib/clevic/cache_table.rb +55 -165
- data/lib/clevic/db_options.rb +32 -21
- data/lib/clevic/default_view.rb +66 -0
- data/lib/clevic/delegates.rb +51 -67
- data/lib/clevic/dirty.rb +101 -0
- data/lib/clevic/extensions.rb +24 -38
- data/lib/clevic/field.rb +400 -99
- data/lib/clevic/item_delegate.rb +32 -33
- data/lib/clevic/model_builder.rb +315 -148
- data/lib/clevic/order_attribute.rb +53 -0
- data/lib/clevic/record.rb +57 -57
- data/lib/clevic/search_dialog.rb +71 -67
- data/lib/clevic/sql_dialects.rb +33 -0
- data/lib/clevic/table_model.rb +73 -120
- data/lib/clevic/table_searcher.rb +165 -0
- data/lib/clevic/table_view.rb +140 -100
- data/lib/clevic/ui/.gitignore +1 -0
- data/lib/clevic/ui/browser_ui.rb +55 -56
- data/lib/clevic/ui/search_dialog_ui.rb +50 -51
- data/lib/clevic/version.rb +2 -2
- data/lib/clevic/view.rb +89 -0
- data/models/accounts_models.rb +12 -9
- data/models/minimal_models.rb +4 -2
- data/models/times_models.rb +41 -25
- data/models/times_sqlite_models.rb +1 -145
- data/models/values_models.rb +15 -16
- data/test/test_cache_table.rb +138 -0
- data/test/test_helper.rb +131 -0
- data/test/test_model_index_extensions.rb +22 -0
- data/test/test_order_attribute.rb +62 -0
- data/test/test_sql_dialects.rb +77 -0
- data/test/test_table_searcher.rb +188 -0
- metadata +36 -20
- data/bin/import-times +0 -128
- data/config/jamis.rb +0 -589
- data/env.sh +0 -1
- data/lib/active_record/dirty.rb +0 -87
- data/lib/clevic/field_builder.rb +0 -42
- data/website/index.html +0 -170
- data/website/index.txt +0 -17
- data/website/screenshot.png +0 -0
- data/website/stylesheets/screen.css +0 -131
- data/website/template.html.erb +0 -41
data/test/test_helper.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'shoulda'
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + '/../lib/clevic'
|
5
|
+
|
6
|
+
require 'activerecord'
|
7
|
+
require 'sqlite3'
|
8
|
+
require 'faker'
|
9
|
+
require 'generator'
|
10
|
+
|
11
|
+
|
12
|
+
class Flight < ActiveRecord::Base
|
13
|
+
has_many :passengers
|
14
|
+
end
|
15
|
+
|
16
|
+
class Passenger < ActiveRecord::Base
|
17
|
+
belongs_to :flight
|
18
|
+
end
|
19
|
+
|
20
|
+
class CreateFlights < ActiveRecord::Migration
|
21
|
+
def self.up
|
22
|
+
create_table :flights do |t|
|
23
|
+
t.string :number
|
24
|
+
t.string :airline
|
25
|
+
t.string :destination
|
26
|
+
end
|
27
|
+
Flight.reset_column_information
|
28
|
+
Flight.create :number => 'EK211'
|
29
|
+
Flight.create :number => 'EK088'
|
30
|
+
Flight.create :number => 'EK761'
|
31
|
+
Flight.create :number => 'BA264'
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.down
|
35
|
+
Flight.delete_all
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class CreatePassengers < ActiveRecord::Migration
|
40
|
+
def self.up
|
41
|
+
create_table :passengers do |t|
|
42
|
+
t.string :name
|
43
|
+
t.string :nationality
|
44
|
+
t.integer :flight_id
|
45
|
+
t.integer :row
|
46
|
+
t.string :seat
|
47
|
+
end
|
48
|
+
Passenger.reset_column_information
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.down
|
52
|
+
Passenger.delete_all
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Convenience class to create a test DB
|
57
|
+
class OneBase
|
58
|
+
attr_reader :db_name, :adapter
|
59
|
+
|
60
|
+
def initialize
|
61
|
+
@db_name = 'test_cache_table.sqlite3'
|
62
|
+
|
63
|
+
if File.exists? @db_name
|
64
|
+
p 'remove old db'
|
65
|
+
File.unlink @db_name
|
66
|
+
end
|
67
|
+
|
68
|
+
@adapter = :sqlite3
|
69
|
+
@db = SQLite3::Database.new( @db_name )
|
70
|
+
@db_options = Clevic::DbOptions.connect do |dbo|
|
71
|
+
dbo.database @db_name
|
72
|
+
dbo.adapter @adapter
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def feenesh
|
77
|
+
File.unlink @db_name
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Allow running of startup and shutdown things before
|
82
|
+
# an entire suite, instead of just one per test
|
83
|
+
class SuiteWrapper < Test::Unit::TestSuite
|
84
|
+
attr_accessor :tests
|
85
|
+
|
86
|
+
def initialize( name, test_case )
|
87
|
+
super( name )
|
88
|
+
@test_case = test_case
|
89
|
+
end
|
90
|
+
|
91
|
+
def startup
|
92
|
+
@onebase = OneBase.new
|
93
|
+
ActiveRecord::Migration.verbose = false
|
94
|
+
CreateFlights.up
|
95
|
+
CreatePassengers.up
|
96
|
+
end
|
97
|
+
|
98
|
+
def shutdown
|
99
|
+
CreatePassengers.down
|
100
|
+
CreateFlights.down
|
101
|
+
@onebase.feenesh
|
102
|
+
end
|
103
|
+
|
104
|
+
def run( *args )
|
105
|
+
startup
|
106
|
+
@test_case.startup if @test_case.respond_to? :startup
|
107
|
+
retval = super
|
108
|
+
@test_case.shutdown if @test_case.respond_to? :shutdown
|
109
|
+
shutdown
|
110
|
+
retval
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
module Test
|
115
|
+
module Unit
|
116
|
+
class TestCase
|
117
|
+
unless respond_to? :old_suite
|
118
|
+
class << self
|
119
|
+
alias_method :old_suite, :suite
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.suite
|
123
|
+
os = old_suite
|
124
|
+
sw = SuiteWrapper.new( os.name, self )
|
125
|
+
sw.tests = os.tests
|
126
|
+
sw
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class TestModelIndex < Test::Unit::TestCase
|
4
|
+
def self.startup
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.shutdown
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
end
|
15
|
+
|
16
|
+
should_eventually 'test something'
|
17
|
+
|
18
|
+
should 'be true' do
|
19
|
+
assert true
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
require 'clevic/order_attribute.rb'
|
3
|
+
|
4
|
+
class Dummy < ActiveRecord::Base
|
5
|
+
end
|
6
|
+
|
7
|
+
# need to set up a test DB, and test data for this
|
8
|
+
class TestOrderAttribute < Test::Unit::TestCase
|
9
|
+
def setup
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_reverse
|
16
|
+
oa = OrderAttribute.new Dummy, 'id'
|
17
|
+
assert_equal :asc, oa.reverse( :desc )
|
18
|
+
assert_equal :desc, oa.reverse( :asc )
|
19
|
+
assert_raise( RuntimeError ) { oa.reverse( :something_wrong ) }
|
20
|
+
end
|
21
|
+
|
22
|
+
# Test that initialisation was OK
|
23
|
+
def test_equal
|
24
|
+
oa1 = OrderAttribute.new Dummy, 'id'
|
25
|
+
oa2 = OrderAttribute.new Dummy, 'id'
|
26
|
+
assert_equal oa1, oa2
|
27
|
+
assert_equal oa1.to_sql, 'dummies.id asc'
|
28
|
+
assert_equal oa1.to_reverse_sql, 'dummies.id desc'
|
29
|
+
assert_equal oa1.attribute.to_sym, oa1.to_sym
|
30
|
+
|
31
|
+
assert_equal oa2.to_sql, 'dummies.id asc'
|
32
|
+
assert_equal oa2.to_reverse_sql, 'dummies.id desc'
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_parse_default
|
36
|
+
oa_asc = OrderAttribute.new Dummy, "name"
|
37
|
+
assert_equal 'name', oa_asc.attribute
|
38
|
+
assert_equal :asc, oa_asc.direction
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_parse_desc
|
42
|
+
oa_desc = OrderAttribute.new Dummy, "name desc"
|
43
|
+
assert_equal 'name', oa_desc.attribute
|
44
|
+
assert_equal 'name', oa_desc.to_s
|
45
|
+
assert_equal :desc, oa_desc.direction
|
46
|
+
assert_equal oa_desc.to_sql, 'dummies.name desc'
|
47
|
+
assert_equal 'dummies.name asc', oa_desc.to_reverse_sql
|
48
|
+
|
49
|
+
oa_desc = OrderAttribute.new Dummy, "dummies.name desc"
|
50
|
+
assert_equal 'name', oa_desc.attribute
|
51
|
+
assert_equal :desc, oa_desc.direction
|
52
|
+
assert_equal oa_desc.to_sql, 'dummies.name desc'
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_parse_table
|
56
|
+
oa_with_table = OrderAttribute.new Dummy, 'dummies.name asc'
|
57
|
+
assert_equal 'name', oa_with_table.attribute
|
58
|
+
assert_equal :asc, oa_with_table.direction
|
59
|
+
assert_equal oa_with_table.to_sql, 'dummies.name asc'
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
require 'clevic/sql_dialects.rb'
|
3
|
+
|
4
|
+
# TODO should probably connect to real DB drivers to do this
|
5
|
+
|
6
|
+
class MockPostgreSQL
|
7
|
+
include Clevic::SqlDialects
|
8
|
+
def adapter_name
|
9
|
+
'PostgreSQL'
|
10
|
+
end
|
11
|
+
|
12
|
+
def connection
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
class MockOther
|
19
|
+
include Clevic::SqlDialects
|
20
|
+
def adapter_name
|
21
|
+
'Something else entirely'
|
22
|
+
end
|
23
|
+
|
24
|
+
def connection
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def quoted_true; "'t'"; end
|
29
|
+
def quoted_false; "'f'"; end
|
30
|
+
end
|
31
|
+
|
32
|
+
class TestSqlDialects < Test::Unit::TestCase
|
33
|
+
def self.startup
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.shutdown
|
37
|
+
end
|
38
|
+
|
39
|
+
def setup
|
40
|
+
end
|
41
|
+
|
42
|
+
context MockPostgreSQL.name do
|
43
|
+
setup do
|
44
|
+
@dialect = MockPostgreSQL.new
|
45
|
+
end
|
46
|
+
|
47
|
+
should 'return ilike' do
|
48
|
+
assert_equal 'ilike', @dialect.like_operator
|
49
|
+
end
|
50
|
+
|
51
|
+
should "return true" do
|
52
|
+
assert_equal "true", @dialect.sql_boolean( true )
|
53
|
+
end
|
54
|
+
|
55
|
+
should "return false" do
|
56
|
+
assert_equal "false", @dialect.sql_boolean( false )
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context MockOther.name do
|
61
|
+
setup do
|
62
|
+
@dialect = MockOther.new
|
63
|
+
end
|
64
|
+
|
65
|
+
should 'return like' do
|
66
|
+
assert_equal 'like', @dialect.like_operator
|
67
|
+
end
|
68
|
+
|
69
|
+
should "return 't'" do
|
70
|
+
assert_equal "'t'", @dialect.sql_boolean( true )
|
71
|
+
end
|
72
|
+
|
73
|
+
should "return 'f'" do
|
74
|
+
assert_equal "'f'", @dialect.sql_boolean( false )
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
require 'clevic/table_searcher.rb'
|
3
|
+
|
4
|
+
class CreateFakePassengers < ActiveRecord::Migration
|
5
|
+
MAX_PASSENGERS = 100
|
6
|
+
NATIONALITIES = %w{Canada USA Britain UAE}
|
7
|
+
|
8
|
+
def self.up
|
9
|
+
1.upto( MAX_PASSENGERS ) do |i|
|
10
|
+
Passenger.create :name => Faker::Name.name, :flight => Flight.find(:all)[i%4], :nationality => NATIONALITIES[i%4], :row => i, :seat => %w{A B C D}[i % 4]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.down
|
15
|
+
Passenger.delete_all
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class MockSearchCriteria
|
20
|
+
|
21
|
+
def initialize( &block )
|
22
|
+
@direction = :forwards
|
23
|
+
@from_start = false
|
24
|
+
@whole_words = false
|
25
|
+
self.instance_eval( &block ) if block_given?
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_accessor :direction, :search_text
|
29
|
+
attr_writer :whole_words, :from_start
|
30
|
+
def whole_words?; @whole_words; end
|
31
|
+
def from_start?; @from_start; end
|
32
|
+
end
|
33
|
+
|
34
|
+
class TestTableSearcher < Test::Unit::TestCase
|
35
|
+
def self.startup
|
36
|
+
CreateFakePassengers.up
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.shutdown
|
40
|
+
CreateFakePassengers.down
|
41
|
+
end
|
42
|
+
|
43
|
+
def setup
|
44
|
+
@simple_search_criteria = MockSearchCriteria.new
|
45
|
+
@id_order_attribute = OrderAttribute.new( Passenger, 'id' )
|
46
|
+
|
47
|
+
@name_field = Clevic::Field.new( :name, Passenger, {} )
|
48
|
+
@nationality_field = Clevic::Field.new( :nationality, Passenger, {} )
|
49
|
+
@all_passengers = Passenger.find( :all, :conditions => [ 'flight_id = ?', Flight.find(:first).id ], :order => :id )
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'on initialisation' do
|
53
|
+
should "have a matching field attribute on construction" do
|
54
|
+
ts = Clevic::TableSearcher.new( Passenger, [@id_order_attribute], @simple_search_criteria, @name_field )
|
55
|
+
assert_equal @name_field.attribute, ts.field.attribute
|
56
|
+
end
|
57
|
+
|
58
|
+
should "throw an exception when called with no order attributes" do
|
59
|
+
assert_raise( RuntimeError ) do
|
60
|
+
Clevic::TableSearcher.new( Passenger, nil, @simple_search_criteria, @name_field )
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
should "throw an exception when called with an empty collection of order attributes" do
|
65
|
+
assert_raise( RuntimeError ) do
|
66
|
+
Clevic::TableSearcher.new( Passenger, [], @simple_search_criteria, @name_field )
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
should "throw an exception when called with no field" do
|
71
|
+
assert_raise( RuntimeError ) do
|
72
|
+
Clevic::TableSearcher.new( Passenger, [@id_order_attribute], @simple_search_criteria, nil )
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
should 'throw an exception for an unknown direction' do
|
77
|
+
@simple_search_criteria.direction = :other
|
78
|
+
assert_raise( RuntimeError ) do
|
79
|
+
table_searcher = Clevic::TableSearcher.new( Passenger, [@id_order_attribute], @simple_search_criteria, @nationality_field )
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "searching" do
|
85
|
+
setup do
|
86
|
+
@simple_search_criteria.search_text = CreateFakePassengers::NATIONALITIES[0]
|
87
|
+
@passenger_generator = Generator.new( @all_passengers )
|
88
|
+
end
|
89
|
+
|
90
|
+
should "have #{CreateFakePassengers::MAX_PASSENGERS} passengers" do
|
91
|
+
assert_equal CreateFakePassengers::MAX_PASSENGERS, Passenger.count
|
92
|
+
end
|
93
|
+
|
94
|
+
should_eventually "do more granular testing"
|
95
|
+
|
96
|
+
should "find the first record" do
|
97
|
+
@simple_search_criteria.from_start = true
|
98
|
+
table_searcher = Clevic::TableSearcher.new( Passenger, [@id_order_attribute], @simple_search_criteria, @nationality_field )
|
99
|
+
assert_equal @all_passengers.first, table_searcher.search
|
100
|
+
end
|
101
|
+
|
102
|
+
should "backwards-find the last record" do
|
103
|
+
@simple_search_criteria.from_start = true
|
104
|
+
@simple_search_criteria.direction = :backwards
|
105
|
+
table_searcher = Clevic::TableSearcher.new( Passenger, [@id_order_attribute], @simple_search_criteria, @nationality_field )
|
106
|
+
assert_equal @all_passengers.last, table_searcher.search
|
107
|
+
end
|
108
|
+
|
109
|
+
should "backwards-find the next-to-last record" do
|
110
|
+
# find the last record
|
111
|
+
@simple_search_criteria.from_start = true
|
112
|
+
@simple_search_criteria.direction = :backwards
|
113
|
+
table_searcher = Clevic::TableSearcher.new( Passenger, [@id_order_attribute], @simple_search_criteria, @nationality_field )
|
114
|
+
last = table_searcher.search
|
115
|
+
|
116
|
+
# now find the previous record
|
117
|
+
@simple_search_criteria.from_start = false
|
118
|
+
assert_equal @all_passengers[-2], table_searcher.search( last )
|
119
|
+
end
|
120
|
+
|
121
|
+
should "find next records" do
|
122
|
+
@simple_search_criteria.from_start = false
|
123
|
+
table_searcher = Clevic::TableSearcher.new( Passenger, [@id_order_attribute], @simple_search_criteria, @nationality_field )
|
124
|
+
|
125
|
+
# fetch records one by one, starting from the one after the first one, and compare them
|
126
|
+
while next_entity = table_searcher.search( @passenger_generator.next )
|
127
|
+
passenger = @passenger_generator.next
|
128
|
+
|
129
|
+
assert_equal next_entity, passenger
|
130
|
+
assert_not_equal @all_passengers.first, passenger
|
131
|
+
|
132
|
+
last_entity = next_entity
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'search for related field value' do
|
138
|
+
should 'raise an exception for no display value' do
|
139
|
+
@simple_search_criteria.from_start = true
|
140
|
+
@simple_search_criteria.search_text = Flight.find(:first).number
|
141
|
+
flight_field = Clevic::Field.new( :flight, Passenger, {} )
|
142
|
+
assert_nil flight_field.path
|
143
|
+
assert_raise RuntimeError do
|
144
|
+
table_searcher = Clevic::TableSearcher.new( Passenger, [@id_order_attribute], @simple_search_criteria, flight_field )
|
145
|
+
table_searcher.search
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
should 'find a record' do
|
150
|
+
@simple_search_criteria.from_start = true
|
151
|
+
@simple_search_criteria.search_text = Flight.find(:first).number
|
152
|
+
flight_field = Clevic::Field.new( :flight, Passenger, { :display => 'number' } )
|
153
|
+
table_searcher = Clevic::TableSearcher.new( Passenger, [@id_order_attribute], @simple_search_criteria, flight_field )
|
154
|
+
assert_equal @all_passengers.first, table_searcher.search
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'whole words' do
|
159
|
+
setup do
|
160
|
+
@simple_search_criteria.from_start = true
|
161
|
+
@simple_search_criteria.search_text = CreateFakePassengers::NATIONALITIES[0][0..-3]
|
162
|
+
@should_find = Passenger.find :all, :conditions => "nationality like '%#{@simple_search_criteria.search_text}%'", :order => :id
|
163
|
+
end
|
164
|
+
|
165
|
+
should 'find a full value with a partial search string' do
|
166
|
+
@simple_search_criteria.whole_words = false
|
167
|
+
@simple_search_criteria.from_start = true
|
168
|
+
table_searcher = Clevic::TableSearcher.new( Passenger, [@id_order_attribute], @simple_search_criteria, @nationality_field )
|
169
|
+
g = Generator.new @should_find
|
170
|
+
last_entity = nil
|
171
|
+
while next_entity = table_searcher.search( last_entity )
|
172
|
+
assert_equal next_entity, g.next
|
173
|
+
last_entity = next_entity
|
174
|
+
@simple_search_criteria.from_start = false
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
should 'not find any values with a partial search string and whole_words enabled' do
|
179
|
+
@simple_search_criteria.whole_words = true
|
180
|
+
@simple_search_criteria.from_start = true
|
181
|
+
table_searcher = Clevic::TableSearcher.new( Passenger, [@id_order_attribute], @simple_search_criteria, @nationality_field )
|
182
|
+
assert_nil table_searcher.search
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
should_eventually 'work for Array'
|
187
|
+
|
188
|
+
end
|