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.
Files changed (52) hide show
  1. data/History.txt +9 -0
  2. data/Manifest.txt +13 -10
  3. data/README.txt +6 -9
  4. data/Rakefile +35 -24
  5. data/TODO +29 -17
  6. data/bin/clevic +84 -37
  7. data/config/hoe.rb +7 -3
  8. data/lib/clevic.rb +2 -4
  9. data/lib/clevic/browser.rb +37 -49
  10. data/lib/clevic/cache_table.rb +55 -165
  11. data/lib/clevic/db_options.rb +32 -21
  12. data/lib/clevic/default_view.rb +66 -0
  13. data/lib/clevic/delegates.rb +51 -67
  14. data/lib/clevic/dirty.rb +101 -0
  15. data/lib/clevic/extensions.rb +24 -38
  16. data/lib/clevic/field.rb +400 -99
  17. data/lib/clevic/item_delegate.rb +32 -33
  18. data/lib/clevic/model_builder.rb +315 -148
  19. data/lib/clevic/order_attribute.rb +53 -0
  20. data/lib/clevic/record.rb +57 -57
  21. data/lib/clevic/search_dialog.rb +71 -67
  22. data/lib/clevic/sql_dialects.rb +33 -0
  23. data/lib/clevic/table_model.rb +73 -120
  24. data/lib/clevic/table_searcher.rb +165 -0
  25. data/lib/clevic/table_view.rb +140 -100
  26. data/lib/clevic/ui/.gitignore +1 -0
  27. data/lib/clevic/ui/browser_ui.rb +55 -56
  28. data/lib/clevic/ui/search_dialog_ui.rb +50 -51
  29. data/lib/clevic/version.rb +2 -2
  30. data/lib/clevic/view.rb +89 -0
  31. data/models/accounts_models.rb +12 -9
  32. data/models/minimal_models.rb +4 -2
  33. data/models/times_models.rb +41 -25
  34. data/models/times_sqlite_models.rb +1 -145
  35. data/models/values_models.rb +15 -16
  36. data/test/test_cache_table.rb +138 -0
  37. data/test/test_helper.rb +131 -0
  38. data/test/test_model_index_extensions.rb +22 -0
  39. data/test/test_order_attribute.rb +62 -0
  40. data/test/test_sql_dialects.rb +77 -0
  41. data/test/test_table_searcher.rb +188 -0
  42. metadata +36 -20
  43. data/bin/import-times +0 -128
  44. data/config/jamis.rb +0 -589
  45. data/env.sh +0 -1
  46. data/lib/active_record/dirty.rb +0 -87
  47. data/lib/clevic/field_builder.rb +0 -42
  48. data/website/index.html +0 -170
  49. data/website/index.txt +0 -17
  50. data/website/screenshot.png +0 -0
  51. data/website/stylesheets/screen.css +0 -131
  52. data/website/template.html.erb +0 -41
data/env.sh DELETED
@@ -1 +0,0 @@
1
- export RUBYLIB=$RUBYLIB:`pwd`/lib
@@ -1,87 +0,0 @@
1
- module ActiveRecord
2
- # Track unsaved changes.
3
- module Dirty
4
- def self.included(base)
5
- base.attribute_method_suffix '_changed?', '_change', '_original'
6
- base.alias_method_chain :read_attribute, :dirty
7
- base.alias_method_chain :write_attribute, :dirty
8
- base.alias_method_chain :save, :dirty
9
- end
10
-
11
- # Do any attributes have unsaved changes?
12
- # person.changed? # => false
13
- # person.name = 'bob'
14
- # person.changed? # => true
15
- def changed?
16
- !changed_attributes.empty?
17
- end
18
-
19
- # List of attributes with unsaved changes.
20
- # person.changed # => []
21
- # person.name = 'bob'
22
- # person.changed # => ['name']
23
- def changed
24
- changed_attributes.keys
25
- end
26
-
27
- # Map of changed attrs => [original value, new value]
28
- # person.changes # => {}
29
- # person.name = 'bob'
30
- # person.changes # => { 'name' => ['bill', 'bob'] }
31
- def changes
32
- changed.inject({}) { |h, attr| h[attr] = attribute_change(attr); h }
33
- end
34
-
35
-
36
- # Clear changed attributes after they are saved.
37
- def save_with_dirty(*args) #:nodoc:
38
- save_without_dirty(*args)
39
- ensure
40
- changed_attributes.clear
41
- end
42
-
43
- private
44
- # Map of change attr => original value.
45
- def changed_attributes
46
- @changed_attributes ||= {}
47
- end
48
-
49
-
50
- # Wrap read_attribute to freeze its result.
51
- def read_attribute_with_dirty(attr)
52
- read_attribute_without_dirty(attr).freeze
53
- end
54
-
55
- # Wrap write_attribute to remember original attribute value.
56
- def write_attribute_with_dirty(attr, value)
57
- attr = attr.to_s
58
-
59
- # The attribute already has an unsaved change.
60
- unless changed_attributes.include?(attr)
61
- old = read_attribute(attr)
62
-
63
- # Remember the original value if it's different.
64
- changed_attributes[attr] = old unless old == value
65
- end
66
-
67
- # Carry on.
68
- write_attribute_without_dirty(attr, value)
69
- end
70
-
71
-
72
- # Handle *_changed? for method_missing.
73
- def attribute_changed?(attr)
74
- changed_attributes.include?(attr)
75
- end
76
-
77
- # Handle *_change for method_missing.
78
- def attribute_change(attr)
79
- [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
80
- end
81
-
82
- # Handle *_original for method_missing.
83
- def attribute_original(attr)
84
- attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr)
85
- end
86
- end
87
- end
@@ -1,42 +0,0 @@
1
- module Clevic
2
-
3
- class BlankSlate
4
- keep_methods = %w( __send__ __id__ send class inspect instance_eval instance_variables )
5
- instance_methods.each do |m|
6
- undef_method(m) unless keep_methods.include?(m)
7
- end
8
- end
9
-
10
- class FieldBuilder < BlankSlate
11
- def initialize( hash = {} )
12
- @hash = hash
13
- end
14
-
15
- # modified from Jim Freeze's article
16
- def self.dsl_accessor(*symbols)
17
- symbols.each do |sym|
18
- line, st = __LINE__, <<EOF
19
- def #{sym}(*val)
20
- if val.empty?
21
- @hash[#{sym.to_sym.inspect}]
22
- else
23
- @hash[#{sym.to_sym.inspect}] = val.size == 1 ? val[0] : val
24
- end
25
- end
26
- EOF
27
- class_eval st, __FILE__, line + 1
28
- end
29
- end
30
-
31
- # originally from Jim Freeze's article
32
- def method_missing(sym, *args)
33
- self.class.dsl_accessor sym
34
- send(sym, *args)
35
- end
36
-
37
- def to_hash
38
- @hash
39
- end
40
- end
41
-
42
- end
@@ -1,170 +0,0 @@
1
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
- <head>
5
- <link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
6
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
7
- <title>
8
- Clevic
9
- </title>
10
- <style>
11
-
12
- </style>
13
- <script type="text/javascript">
14
- window.onload = function() {
15
- settings = {
16
- tl: { radius: 10 },
17
- tr: { radius: 10 },
18
- bl: { radius: 10 },
19
- br: { radius: 10 },
20
- antiAlias: true,
21
- autoPad: true,
22
- validTags: ["div"]
23
- }
24
- }
25
- </script>
26
- </head>
27
- <body>
28
-
29
- <div id="main">
30
- <h1>Clevic</h1>
31
- <p><a href="rdoc">RDoc</a> | <a href="http://rubyforge.org/projects/clevic/">Rubyforge Project</a></p>
32
-
33
-
34
- <p>Code for minimal UI definition</p>
35
-
36
-
37
- <pre><code>
38
- require 'clevic.rb'
39
-
40
- # see sql/accounts.sql for schema
41
-
42
- # db connection
43
- Clevic::DbOptions.connect do
44
- database 'accounts_test'
45
- adapter :postgresql
46
- username 'accounts'
47
- end
48
-
49
- # minimal definition to get combo boxes to show up
50
- class Entry &lt; Clevic::Record
51
- belongs_to :debit, :class_name =&gt; 'Account', :foreign_key =&gt; 'debit_id'
52
- belongs_to :credit, :class_name =&gt; 'Account', :foreign_key =&gt; 'credit_id'
53
- end
54
-
55
- # minimal definition to get sensible values in combo boxes
56
- class Account &lt; Clevic::Record
57
- def to_s; name; end
58
- end
59
-
60
- </code></pre>
61
-
62
- <p>Screenshot of a more fully defined UI with the foreign-key dropdown in place. Tabs contain
63
- the two tables, model definition file is below the screenshot. The Entry
64
- model has some code to do update the credit and debit fields when
65
- the new item description is found in the table.</p>
66
-
67
-
68
- <p><img src="screenshot.png" title="Screenshot" alt="Screenshot" /></p>
69
- </div>
70
-
71
- <pre><code>
72
- require 'clevic.rb'
73
-
74
- # db connection
75
- Clevic::DbOptions.connect( $options ) do
76
- # use a different db for testing, so real data doesn't get broken.
77
- if options[:database].nil? || options[:database].empty?
78
- database( debug? ? :accounts_test : :accounts )
79
- else
80
- database options[:database]
81
- end
82
- adapter :postgresql
83
- username 'accounts'
84
- end
85
-
86
- class Entry < Clevic::Record
87
- belongs_to :debit, :class_name => 'Account', :foreign_key => 'debit_id'
88
- belongs_to :credit, :class_name => 'Account', :foreign_key => 'credit_id'
89
-
90
- define_ui do
91
- plain :date, :sample => '88-WWW-99'
92
- distinct :description, :conditions => "now() - date <= '1 year'", :sample => 'm' * 26
93
- relational :debit, :display => 'name', :conditions => 'active = true', :order => 'lower(name)', :sample => 'Leilani Member Loan'
94
- relational :credit, :display => 'name', :conditions => 'active = true', :order => 'lower(name)', :sample => 'Leilani Member Loan'
95
- plain :amount, :sample => 999999.99
96
- distinct :category
97
- plain :cheque_number
98
- plain :active, :sample => 'WW'
99
- plain :vat, :label => 'VAT', :sample => 'WW', :tooltip => 'Does this include VAT?'
100
-
101
- records :order => 'date, id'
102
- end
103
-
104
- # called when data is changed in the UI
105
- def self.data_changed( top_left, bottom_right, view )
106
- if top_left == bottom_right
107
- update_credit_debit( top_left, view )
108
- else
109
- puts "top_left: #{top_left.inspect}"
110
- puts "bottom_right: #{bottom_right.inspect}"
111
- puts "can't do data_changed for a range"
112
- end
113
- end
114
-
115
- # check that the current field is :descriptions, then
116
- # copy the values for the credit and debit fields
117
- # from the previous similar entry
118
- def self.update_credit_debit( current_index, view )
119
- return if !current_index.valid?
120
- current_field = current_index.attribute
121
- if current_field == :description
122
- # most recent entry, ordered in reverse
123
- similar = self.find(
124
- :first,
125
- :conditions => ["#{current_field} = ?", current_index.attribute_value],
126
- :order => 'date desc'
127
- )
128
- if similar != nil
129
- # set the values
130
- current_index.entity.debit = similar.debit
131
- current_index.entity.credit = similar.credit
132
- current_index.entity.category = similar.category
133
-
134
- # emit signal to update view from top_left to bottom_right
135
- model = current_index.model
136
- top_left_index = model.create_index( current_index.row, 0 )
137
- bottom_right_index = model.create_index( current_index.row, view.builder.fields.size )
138
- view.dataChanged( top_left_index, bottom_right_index )
139
-
140
- # move edit cursor to amount field
141
- view.selection_model.clear
142
- view.override_next_index( model.create_index( current_index.row, view.builder.index( :amount ) ) )
143
- end
144
- end
145
- end
146
- end
147
-
148
- class Account < Clevic::Record
149
- has_many :debits, :class_name => 'Entry', :foreign_key => 'debit_id'
150
- has_many :credits, :class_name => 'Entry', :foreign_key => 'credit_id'
151
-
152
- # define how fields are displayed
153
- define_ui do
154
- plain :name
155
- restricted :vat, :label => 'VAT', :set => %w{ yes no all }
156
- plain :account_type
157
- plain :pastel_number, :alignment => Qt::AlignRight, :label => 'Pastel'
158
- plain :fringe, :format => "%.1f"
159
- plain :active
160
-
161
- records :order => 'name,account_type'
162
- end
163
- end
164
-
165
- </code></pre>
166
-
167
- <!-- insert site tracking codes here, like Google Urchin -->
168
-
169
- </body>
170
- </html>
@@ -1,17 +0,0 @@
1
- h1. Clevic
2
-
3
- "RDoc":rdoc | "Rubyforge Project":http://rubyforge.org/projects/clevic/
4
-
5
- Code for minimal UI definition
6
-
7
- <pre><code>
8
- <%= File.read 'models/minimal_models.rb' %>
9
- </code></pre>
10
-
11
-
12
- Screenshot of a more fully defined UI with the foreign-key dropdown in place. Tabs contain
13
- the two tables, model definition file is below the screenshot. The Entry
14
- model has some code to do update the credit and debit fields when
15
- the new item description is found in the table.
16
-
17
- !screenshot.png(Screenshot)!
Binary file
@@ -1,131 +0,0 @@
1
- body {
2
- font-family: "Georgia", sans-serif;
3
- font-size: 16px;
4
- line-height: 1.6em;
5
- padding: 1.6em 0 0 0;
6
- color: #333;
7
- }
8
- h1, h2, h3, h4, h5, h6 {
9
- color: #444;
10
- }
11
- h1 {
12
- font-family: sans-serif;
13
- font-weight: normal;
14
- font-size: 4em;
15
- line-height: 0.8em;
16
- letter-spacing: -0.1ex;
17
- margin: 5px;
18
- }
19
- li {
20
- padding: 0;
21
- margin: 0;
22
- list-style-type: square;
23
- }
24
- blockquote {
25
- font-size: 90%;
26
- font-style: italic;
27
- border-left: 1px solid #111;
28
- padding-left: 1em;
29
- }
30
- .caps {
31
- font-size: 80%;
32
- }
33
-
34
- #main {
35
- width: 45em;
36
- padding: 0;
37
- margin: 0 auto;
38
- }
39
- .coda {
40
- text-align: right;
41
- color: #77f;
42
- font-size: smaller;
43
- }
44
-
45
- table {
46
- font-size: 90%;
47
- line-height: 1.4em;
48
- color: #ff8;
49
- background-color: #111;
50
- padding: 2px 10px 2px 10px;
51
- border-style: dashed;
52
- }
53
-
54
- th {
55
- color: #fff;
56
- }
57
-
58
- td {
59
- padding: 2px 10px 2px 10px;
60
- }
61
-
62
- .success {
63
- color: #0CC52B;
64
- }
65
-
66
- .failed {
67
- color: #E90A1B;
68
- }
69
-
70
- .unknown {
71
- color: #995000;
72
- }
73
- pre, code {
74
- font-family: monospace;
75
- font-size: 90%;
76
- line-height: 1.4em;
77
- color: #ff8;
78
- background-color: #111;
79
- padding: 2px 10px 2px 10px;
80
- }
81
- .comment { color: #aaa; font-style: italic; }
82
- .keyword { color: #eff; font-weight: bold; }
83
- .punct { color: #eee; font-weight: bold; }
84
- .symbol { color: #0bb; }
85
- .string { color: #6b4; }
86
- .ident { color: #ff8; }
87
- .constant { color: #66f; }
88
- .regex { color: #ec6; }
89
- .number { color: #F99; }
90
- .expr { color: #227; }
91
-
92
- #version {
93
- float: right;
94
- text-align: right;
95
- font-family: sans-serif;
96
- font-weight: normal;
97
- background-color: #B3ABFF;
98
- color: #141331;
99
- padding: 15px 20px 10px 20px;
100
- margin: 0 auto;
101
- margin-top: 15px;
102
- border: 3px solid #141331;
103
- }
104
-
105
- #version .numbers {
106
- display: block;
107
- font-size: 4em;
108
- line-height: 0.8em;
109
- letter-spacing: -0.1ex;
110
- margin-bottom: 15px;
111
- }
112
-
113
- #version p {
114
- text-decoration: none;
115
- color: #141331;
116
- background-color: #B3ABFF;
117
- margin: 0;
118
- padding: 0;
119
- }
120
-
121
- #version a {
122
- text-decoration: none;
123
- color: #141331;
124
- background-color: #B3ABFF;
125
- }
126
-
127
- .clickable {
128
- cursor: pointer;
129
- cursor: hand;
130
- }
131
-