clevic 0.11.1 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +21 -0
- data/Manifest.txt +4 -2
- data/Rakefile +32 -139
- data/TODO +12 -15
- data/bin/clevic +5 -0
- data/lib/clevic/browser.rb +1 -1
- data/lib/clevic/cache_table.rb +15 -34
- data/lib/clevic/default_view.rb +6 -0
- data/lib/clevic/delegates.rb +25 -19
- data/lib/clevic/extensions.rb +1 -1
- data/lib/clevic/field.rb +55 -5
- data/lib/clevic/filter_command.rb +51 -0
- data/lib/clevic/model_builder.rb +40 -23
- data/lib/clevic/table_model.rb +113 -8
- data/lib/clevic/table_view.rb +207 -92
- data/lib/clevic/text_delegate.rb +84 -0
- data/lib/clevic/version.rb +2 -2
- data/lib/clevic/view.rb +28 -2
- data/models/accounts_models.rb +34 -40
- data/models/times_models.rb +69 -33
- data/tasks/clevic.rake +111 -0
- data/tasks/rdoc.rake +16 -0
- data/test/test_cache_table.rb +0 -23
- data/test/test_table_model.rb +61 -0
- data/test/test_table_searcher.rb +1 -1
- metadata +45 -10
- data/config/hoe.rb +0 -82
- data/config/requirements.rb +0 -15
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'clevic/item_delegate.rb'
|
2
|
+
|
3
|
+
module Clevic
|
4
|
+
|
5
|
+
class TextDelegate < ItemDelegate
|
6
|
+
|
7
|
+
# Doesn't do anything useful yet, but I'm leaving
|
8
|
+
# it here so I don't have to change other code.
|
9
|
+
class TextEditor < Qt::PlainTextEdit
|
10
|
+
end
|
11
|
+
|
12
|
+
# this is overridden in Qt::ItemDelegate, but that
|
13
|
+
# always catches the return key. Which we want for text editing.
|
14
|
+
# Instead, we use Ctrl-Enter to save the edited text.
|
15
|
+
# return true if event is handled, false otherwise
|
16
|
+
def eventFilter( object, event )
|
17
|
+
if object.class == TextEditor && event.class == Qt::KeyEvent
|
18
|
+
retval =
|
19
|
+
case
|
20
|
+
when event.ctrl? && ( event.enter? || event.return? )
|
21
|
+
# close and save
|
22
|
+
# copied from QItemDelegate.
|
23
|
+
emit commitData( object )
|
24
|
+
emit closeEditor( object )
|
25
|
+
true
|
26
|
+
|
27
|
+
# send an enter or return to the text editor
|
28
|
+
when event.enter? || event.return?
|
29
|
+
object.event( event )
|
30
|
+
true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
retval || super
|
34
|
+
end
|
35
|
+
|
36
|
+
# maybe open in a separate window?
|
37
|
+
def full_edit
|
38
|
+
puts "#{self.class.name} full_edit"
|
39
|
+
end
|
40
|
+
|
41
|
+
# Override the Qt method
|
42
|
+
def createEditor( parent_widget, style_option_view_item, model_index )
|
43
|
+
if false && model_index.gui_value.count("\n") == 0
|
44
|
+
# futzing about here, really
|
45
|
+
@editor = Qt::LineEdit.new( parent_widget )
|
46
|
+
else
|
47
|
+
@editor = TextEditor.new( parent_widget )
|
48
|
+
@editor.install_event_filter( self )
|
49
|
+
end
|
50
|
+
@editor
|
51
|
+
end
|
52
|
+
|
53
|
+
# Override the Qt::ItemDelegate method.
|
54
|
+
def updateEditorGeometry( editor, style_option_view_item, model_index )
|
55
|
+
rect = Qt::Rect.new( style_option_view_item.rect.top_left, style_option_view_item.rect.size )
|
56
|
+
|
57
|
+
# ask the editor for how much space it wants, and set the editor
|
58
|
+
# to that size when it displays in the table
|
59
|
+
rect.set_width( [editor.size_hint.width,rect.width].max )
|
60
|
+
rect.set_height( editor.size_hint.height )
|
61
|
+
|
62
|
+
unless editor.parent.rect.contains( rect )
|
63
|
+
# 46 because TableView returns an incorrect bottom.
|
64
|
+
# And I can't find out how to get the correct value.
|
65
|
+
rect.move_bottom( parent.contents_rect.bottom - 46 )
|
66
|
+
end
|
67
|
+
editor.set_geometry( rect )
|
68
|
+
end
|
69
|
+
|
70
|
+
# Override the Qt method to send data to the editor from the model.
|
71
|
+
def setEditorData( editor, model_index )
|
72
|
+
editor.plain_text = model_index.gui_value
|
73
|
+
end
|
74
|
+
|
75
|
+
# Send the data from the editor to the model. The data will
|
76
|
+
# be translated by translate_from_editor_text,
|
77
|
+
def setModelData( editor, abstract_item_model, model_index )
|
78
|
+
model_index.attribute_value = editor.to_plain_text
|
79
|
+
abstract_item_model.data_changed( model_index )
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
data/lib/clevic/version.rb
CHANGED
data/lib/clevic/view.rb
CHANGED
@@ -77,8 +77,34 @@ module Clevic
|
|
77
77
|
def define_actions( table_view, action_builder )
|
78
78
|
end
|
79
79
|
|
80
|
-
#
|
81
|
-
def
|
80
|
+
# notify
|
81
|
+
def notify_field( table_view, model_index )
|
82
|
+
ndc = model_index.field.notify_data_changed
|
83
|
+
case ndc
|
84
|
+
when Proc
|
85
|
+
ndc.call( self, table_view, model_index )
|
86
|
+
|
87
|
+
when Symbol
|
88
|
+
send( ndc, table_view, model_index )
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Define data changed events. Default is to call notify_data_changed
|
93
|
+
# for each field in the rectangular area defined by top_left and bottom_right
|
94
|
+
# (which are Qt::ModelIndex instances)
|
95
|
+
def notify_data_changed( table_view, top_left, bottom_right )
|
96
|
+
if top_left == bottom_right
|
97
|
+
# shortcut to just the one, seeing as it's probably the most common
|
98
|
+
notify_field( table_view, top_left )
|
99
|
+
else
|
100
|
+
# do the entire rectagular area
|
101
|
+
(top_left.row..bottom_right.row).each do |row_index|
|
102
|
+
(top_left.column..bottom_right.column).each do |column_index|
|
103
|
+
model_index = table_view.model.create_index( row_index, column_index )
|
104
|
+
notify_field( table_view, model_index )
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
82
108
|
end
|
83
109
|
|
84
110
|
# be notified of key presses
|
data/models/accounts_models.rb
CHANGED
@@ -9,7 +9,7 @@ Clevic::DbOptions.connect( $options ) do
|
|
9
9
|
database options[:database]
|
10
10
|
end
|
11
11
|
adapter :postgresql
|
12
|
-
username 'accounts'
|
12
|
+
username options[:username].blank? ? 'accounts' : options[:username]
|
13
13
|
end
|
14
14
|
|
15
15
|
class Entry < ActiveRecord::Base
|
@@ -20,7 +20,19 @@ class Entry < ActiveRecord::Base
|
|
20
20
|
|
21
21
|
define_ui do
|
22
22
|
plain :date, :sample => '88-WWW-99'
|
23
|
-
distinct :description
|
23
|
+
distinct :description do |f|
|
24
|
+
f.conditions "now() - date <= '1 year'"
|
25
|
+
f.sample( 'm' * 26 )
|
26
|
+
f.notify_data_changed = lambda do |entity_view, table_view, model_index|
|
27
|
+
if model_index.entity.credit.nil? && model_index.entity.debit.nil?
|
28
|
+
entity_view.update_from_description( model_index )
|
29
|
+
|
30
|
+
# move edit cursor to amount field
|
31
|
+
table_view.selection_model.clear
|
32
|
+
table_view.override_next_index( model_index.choppy( :column => :amount ) )
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
24
36
|
relational :debit, :display => 'name', :conditions => 'active = true', :order => 'lower(name)', :sample => 'Leilani Member Loan'
|
25
37
|
relational :credit, :display => 'name', :conditions => 'active = true', :order => 'lower(name)', :sample => 'Leilani Member Loan'
|
26
38
|
plain :amount, :sample => 999999.99
|
@@ -32,44 +44,26 @@ class Entry < ActiveRecord::Base
|
|
32
44
|
records :order => 'date, id'
|
33
45
|
end
|
34
46
|
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
:first,
|
56
|
-
:conditions => ["#{current_field} = ?", current_index.attribute_value],
|
57
|
-
:order => 'date desc'
|
58
|
-
)
|
59
|
-
if similar != nil
|
60
|
-
# set the values
|
61
|
-
current_index.entity.debit = similar.debit
|
62
|
-
current_index.entity.credit = similar.credit
|
63
|
-
current_index.entity.category = similar.category
|
64
|
-
|
65
|
-
# emit signal to update view from top_left to bottom_right
|
66
|
-
top_left_index = current_index.choppy( :column => 0 )
|
67
|
-
bottom_right_index = current_index.choppy( :column => view.model.column_count - 1 )
|
68
|
-
view.dataChanged( top_left_index, bottom_right_index )
|
69
|
-
|
70
|
-
# move edit cursor to amount field
|
71
|
-
view.selection_model.clear
|
72
|
-
view.override_next_index( current_index.choppy( :column => view.field_column( :amount ) ) )
|
47
|
+
# Copy the values for the credit and debit fields
|
48
|
+
# from the previous similar entry with a similar description
|
49
|
+
def self.update_from_description( current_index )
|
50
|
+
return if current_index.attribute_value.nil?
|
51
|
+
# most recent entry, ordered in reverse
|
52
|
+
similar = self.find(
|
53
|
+
:first,
|
54
|
+
:conditions => ["#{current_index.attribute} = ?", current_index.attribute_value],
|
55
|
+
:order => 'date desc'
|
56
|
+
)
|
57
|
+
if similar != nil
|
58
|
+
# set the values
|
59
|
+
current_index.entity.debit = similar.debit
|
60
|
+
current_index.entity.credit = similar.credit
|
61
|
+
current_index.entity.category = similar.category
|
62
|
+
|
63
|
+
# emit signal to that whole row has changed
|
64
|
+
current_index.model.data_changed do |change|
|
65
|
+
change.top_left = current_index.choppy( :column => 0 )
|
66
|
+
change.bottom_right = current_index.choppy( :column => current_index.model.column_count - 1 )
|
73
67
|
end
|
74
68
|
end
|
75
69
|
end
|
data/models/times_models.rb
CHANGED
@@ -19,11 +19,35 @@ class Entry < ActiveRecord::Base
|
|
19
19
|
|
20
20
|
define_ui do
|
21
21
|
plain :date, :sample => '28-Dec-08'
|
22
|
-
|
22
|
+
|
23
|
+
# The project field
|
24
|
+
relational :project do |field|
|
25
|
+
field.display = 'project'
|
26
|
+
field.conditions = 'active = true'
|
27
|
+
field.order = 'lower(project)'
|
28
|
+
|
29
|
+
# handle data changed events. In this case,
|
30
|
+
# auto-fill-in the invoice field.
|
31
|
+
field.notify_data_changed do |entity_view, table_view, model_index|
|
32
|
+
if model_index.entity.invoice.nil?
|
33
|
+
entity_view.invoice_from_project( table_view, model_index ) do
|
34
|
+
# move here next if the invoice was changed
|
35
|
+
table_view.override_next_index model_index.choppy( :column => :start )
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
23
41
|
relational :invoice, :display => 'invoice_number', :conditions => "status = 'not sent'", :order => 'invoice_number'
|
42
|
+
|
43
|
+
# call time_color method for foreground color value
|
24
44
|
plain :start, :foreground => :time_color, :tooltip => :time_tooltip
|
45
|
+
|
46
|
+
# another way to call time_color method for foreground color value
|
25
47
|
plain :end, :foreground => lambda{|x| x.time_color}, :tooltip => :time_tooltip
|
26
|
-
|
48
|
+
|
49
|
+
# multiline text
|
50
|
+
text :description, :sample => 'This is a long string designed to hold lots of data and description'
|
27
51
|
|
28
52
|
relational :activity do
|
29
53
|
display 'activity'
|
@@ -34,18 +58,25 @@ class Entry < ActiveRecord::Base
|
|
34
58
|
|
35
59
|
distinct :module, :tooltip => 'Module or sub-project'
|
36
60
|
plain :charge, :tooltip => 'Is this time billable?'
|
37
|
-
distinct :person, :tooltip => 'The person who did the work'
|
61
|
+
distinct :person, :default => 'John', :tooltip => 'The person who did the work'
|
38
62
|
|
39
63
|
records :order => 'date, start, id'
|
40
64
|
end
|
41
65
|
|
42
|
-
def self.
|
66
|
+
def self.define_actions( view, action_builder )
|
43
67
|
action_builder.action :smart_copy, 'Smart Copy', :shortcut => 'Ctrl+"' do
|
44
68
|
smart_copy( view )
|
45
69
|
end
|
46
70
|
|
47
71
|
action_builder.action :invoice_from_project, 'Invoice from Project', :shortcut => 'Ctrl+Shift+I' do
|
48
|
-
invoice_from_project( view
|
72
|
+
invoice_from_project( view, view.current_index ) do
|
73
|
+
# execute the block if the invoice is changed
|
74
|
+
|
75
|
+
# save this before selection model is cleared
|
76
|
+
current_index = view.current_index
|
77
|
+
view.selection_model.clear
|
78
|
+
view.current_index = current_index.choppy( :column => :start )
|
79
|
+
end
|
49
80
|
end
|
50
81
|
end
|
51
82
|
|
@@ -54,63 +85,68 @@ class Entry < ActiveRecord::Base
|
|
54
85
|
view.sanity_check_read_only
|
55
86
|
view.sanity_check_ditto
|
56
87
|
|
57
|
-
# need a reference to current_index here, because selection_model.clear will
|
58
|
-
# view.current_index. And anyway, its shorter and easier to read.
|
88
|
+
# need a reference to current_index here, because selection_model.clear will
|
89
|
+
# invalidate view.current_index. And anyway, its shorter and easier to read.
|
59
90
|
current_index = view.current_index
|
60
|
-
if current_index.row
|
91
|
+
if current_index.row >= 1
|
61
92
|
# fetch previous item
|
62
93
|
previous_item = view.model.collection[current_index.row - 1]
|
63
94
|
|
64
95
|
# copy the relevant fields
|
65
|
-
current_index.entity.
|
66
|
-
|
96
|
+
current_index.entity.date = previous_item.date if current_index.entity.date.blank?
|
97
|
+
# depends on previous line
|
98
|
+
current_index.entity.start = previous_item.end if current_index.entity.date == previous_item.date
|
99
|
+
|
100
|
+
# copy rest of fields
|
101
|
+
[:project, :invoice, :activity, :module, :charge, :person].each do |attr|
|
67
102
|
current_index.entity.send( "#{attr.to_s}=", previous_item.send( attr ) )
|
68
103
|
end
|
69
104
|
|
70
105
|
# tell view to update
|
71
|
-
|
72
|
-
|
73
|
-
|
106
|
+
view.model.data_changed do |change|
|
107
|
+
change.top_left = current_index.choppy( :column => 0 )
|
108
|
+
change.bottom_right = current_index.choppy( :column => view.model.fields.size - 1 )
|
109
|
+
end
|
74
110
|
|
75
|
-
# move to
|
76
|
-
view.selection_model.clear
|
111
|
+
# move to the first empty time field
|
77
112
|
next_field =
|
78
113
|
if current_index.entity.start.blank?
|
79
114
|
:start
|
80
115
|
else
|
81
116
|
:end
|
82
117
|
end
|
83
|
-
|
84
|
-
|
118
|
+
|
119
|
+
# next cursor location
|
120
|
+
view.selection_model.clear
|
121
|
+
view.current_index = current_index.choppy( :column => next_field )
|
85
122
|
end
|
86
123
|
end
|
87
124
|
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
# auto-complete invoice number field from project
|
94
|
-
def self.invoice_from_project( current_index, view )
|
95
|
-
current_field = current_index.attribute
|
96
|
-
if [:project,:invoice].include?( current_field ) && current_index.entity.project != nil
|
125
|
+
# Auto-complete invoice number field from project.
|
126
|
+
# &block will be executed if an invoice was assigned
|
127
|
+
# If block takes one parameter, pass the new invoice.
|
128
|
+
def self.invoice_from_project( table_view, current_index, &block )
|
129
|
+
if current_index.entity.project != nil
|
97
130
|
# most recent entry, ordered in reverse
|
98
131
|
invoice = current_index.entity.project.latest_invoice
|
99
|
-
|
100
132
|
unless invoice.nil?
|
101
133
|
# make a reference to the invoice
|
102
134
|
current_index.entity.invoice = invoice
|
103
135
|
|
104
136
|
# update view from top_left to bottom_right
|
105
|
-
|
106
|
-
view.dataChanged( changed_index, changed_index )
|
137
|
+
table_view.model.data_changed( current_index.choppy( :column => :invoice ) )
|
107
138
|
|
108
|
-
|
109
|
-
|
110
|
-
|
139
|
+
unless block.nil?
|
140
|
+
if block.arity == 1
|
141
|
+
block.call( invoice )
|
142
|
+
else
|
143
|
+
block.call
|
144
|
+
end
|
145
|
+
end
|
111
146
|
end
|
112
147
|
end
|
113
148
|
end
|
149
|
+
|
114
150
|
end
|
115
151
|
|
116
152
|
class Invoice < ActiveRecord::Base
|
@@ -123,7 +159,7 @@ class Invoice < ActiveRecord::Base
|
|
123
159
|
plain :invoice_number
|
124
160
|
restricted :status, :set => ['not sent', 'sent', 'paid', 'debt', 'writeoff', 'internal']
|
125
161
|
restricted :billing, :set => %w{Hours Quote Internal}
|
126
|
-
plain :quote_date
|
162
|
+
plain :quote_date, :format => '%d-%b-%y', :edit_format => '%d-%b-%Y', :tooltip => 'the date and time when the quote was supplied', :default => lambda{|x| DateTime.now}
|
127
163
|
plain :quote_amount
|
128
164
|
plain :description
|
129
165
|
|
data/tasks/clevic.rake
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
task :package => :ui
|
2
|
+
|
3
|
+
desc "Update ChangeLog from the SVN log"
|
4
|
+
task :changelog do |t|
|
5
|
+
ARGV.shift
|
6
|
+
exec "svn2cl --break-before-msg -o ChangeLog #{ARGV.join(' ')}"
|
7
|
+
end
|
8
|
+
|
9
|
+
# generate a _ui.rb filename from a .ui filename
|
10
|
+
def ui_rb_file( ui_file )
|
11
|
+
ui_file.gsub( /\.ui$/, '_ui.rb' )
|
12
|
+
end
|
13
|
+
|
14
|
+
# list of .ui files
|
15
|
+
UI_FILES = FileList.new( 'lib/clevic/ui/*.ui' )
|
16
|
+
CLEAN.include( 'ChangeLog', 'coverage', 'profiling' )
|
17
|
+
CLOBBER.include( 'ChangeLog', 'pkg', 'lib/clevic/ui/*_ui.rb' )
|
18
|
+
|
19
|
+
UI_FILES.each do |ui_file|
|
20
|
+
# make tasks to generate _ui.rb files
|
21
|
+
file ui_rb_file( ui_file ) => [ ui_file ] do |t|
|
22
|
+
sh "rbuic4 #{t.prerequisites} -o #{t.name}"
|
23
|
+
end
|
24
|
+
|
25
|
+
# make tasks to start designer when the ui file is named
|
26
|
+
desc "Start Qt designer with #{ui_file}"
|
27
|
+
namespace :ui do |n|
|
28
|
+
task Pathname.new(ui_file).basename.to_s.ext do |t|
|
29
|
+
sh "designer #{ui_file}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc 'Generate all _ui.rb files'
|
35
|
+
task :ui => UI_FILES.map{|x| ui_rb_file( x ) }
|
36
|
+
|
37
|
+
namespace :ui do
|
38
|
+
desc 'Start Qt designer with the argument, or all .ui files.'
|
39
|
+
task :design do |t|
|
40
|
+
ARGV.shift()
|
41
|
+
if ARGV.size == 0
|
42
|
+
# start designer with all ui files
|
43
|
+
sh "designer #{UI_FILES.join(' ')}"
|
44
|
+
else
|
45
|
+
# start designer with all files that match an argument
|
46
|
+
sh "designer #{ ARGV.map{|x| UI_FILES.grep( /\/#{x}/ ) }.join(' ') }"
|
47
|
+
end
|
48
|
+
true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Runs Clevic in normal mode, with live database."
|
53
|
+
task :run => :ui do |t|
|
54
|
+
ARGV.shift()
|
55
|
+
exec "ruby -Ilib bin/clevic #{ARGV.join(' ')}"
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "Runs Clevic in debug mode, with test databases"
|
59
|
+
task :debug => :ui do |t|
|
60
|
+
ARGV.shift()
|
61
|
+
exec "ruby -w -rdebug -Ilib bin/clevic -D #{ARGV.join(' ')}"
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "irb in this project's context"
|
65
|
+
task :irb do |t|
|
66
|
+
ARGV.shift()
|
67
|
+
ENV['RUBYLIB'] ||= ''
|
68
|
+
ENV['RUBYLIB'] += ":#{File.expand_path('.')}/lib"
|
69
|
+
exec "irb -Ilib -rclevic"
|
70
|
+
end
|
71
|
+
|
72
|
+
# generate tasks for all model definition files
|
73
|
+
MODELS_LIST = FileList.new( '**/*models.rb' )
|
74
|
+
|
75
|
+
def short_model( model_file )
|
76
|
+
Pathname.new( model_file ).basename.to_s.gsub( /_models.rb/, '' )
|
77
|
+
end
|
78
|
+
|
79
|
+
MODELS_LIST.each do |model_file|
|
80
|
+
# generate irb contexts
|
81
|
+
desc "irb with #{model_file}"
|
82
|
+
namespace :irb do
|
83
|
+
task short_model( model_file ) do |t|
|
84
|
+
ARGV.shift()
|
85
|
+
ARGV.shift() if ARGV[0] == '--'
|
86
|
+
ENV['RUBYLIB'] ||= '.'
|
87
|
+
ENV['RUBYLIB'] += ":#{File.expand_path('.')}/lib"
|
88
|
+
exec "irb -Ilib -rclevic -r#{model_file} -rclevic/db_options.rb"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# generate runs
|
93
|
+
namespace :run do
|
94
|
+
desc "run clevic with #{model_file}"
|
95
|
+
task short_model( model_file ) => :ui do |t|
|
96
|
+
ARGV.shift()
|
97
|
+
ARGV.shift() if ARGV[0] == '--'
|
98
|
+
cmd = "ruby -Ilib bin/clevic -D #{model_file} #{ARGV.join(' ')}"
|
99
|
+
puts "cmd: #{cmd.inspect}"
|
100
|
+
exec cmd
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
namespace :warn do
|
105
|
+
desc "run clevic with #{model_file} and warnings on"
|
106
|
+
task short_model( model_file ) => :ui do |t|
|
107
|
+
ARGV.shift()
|
108
|
+
exec "ruby -w -Ilib bin/clevic -D #{model_file} #{ARGV.join(' ')}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|