hydra-tutorial 0.1.3 → 0.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 (33) hide show
  1. data/.gitignore +2 -0
  2. data/README.md +92 -22
  3. data/bin/hydra-tutorial +4 -2
  4. data/development_notes.txt +476 -0
  5. data/hydra-tutorial.gemspec +9 -11
  6. data/{templates → old_tutorial/templates}/application/dataset_hydra_mods_om.rb +0 -0
  7. data/{templates → old_tutorial/templates}/application/dataset_hydra_om.rb +0 -0
  8. data/{templates → old_tutorial/templates}/application/datasets_controller.rb +0 -0
  9. data/{or_templates/adding_our_models → old_tutorial/templates/application}/mods_desc_metadata.rb +0 -0
  10. data/{templates → old_tutorial/templates}/building_a_basic_rails_app/dataset_af_om.rb +0 -0
  11. data/{templates → old_tutorial/templates}/building_a_basic_rails_app/dataset_simple_om.rb +0 -0
  12. data/{or_templates → old_tutorial/templates}/building_a_basic_rails_app/fedora.yml +0 -0
  13. data/{templates → old_tutorial/templates}/building_a_basic_rails_app/om_record.rb +0 -0
  14. data/{or_templates → old_tutorial/templates}/building_a_basic_rails_app/solr.yml +0 -0
  15. data/old_tutorial/tutorial.thor +493 -0
  16. data/{or_templates/sprinkle_some_styling → templates}/_add_assets_links.html.erb +0 -0
  17. data/{or_templates/add_file_upload/_form.html.erb → templates/_form.add_file_upload.html.erb} +0 -0
  18. data/{or_templates/wiring_it_into_rails/_form.html.erb → templates/_form.wiring_it_into_rails.html.erb} +0 -0
  19. data/{or_templates/adding_our_models → templates}/basic_af_model.rb +0 -0
  20. data/{or_templates/adding_our_models → templates}/basic_mods_model.rb +0 -0
  21. data/{or_templates/adding_our_models → templates}/basic_om_model.rb +0 -0
  22. data/{or_templates/add_tests → templates}/ci.rake +0 -0
  23. data/{or_templates/add_tests → templates}/ci_with_coverage.rake +0 -0
  24. data/templates/{building_a_basic_rails_app/fedora.yml → fedora.yml} +0 -0
  25. data/{or_templates/add_tests → templates}/integration_spec.rb +0 -0
  26. data/templates/{application/mods_desc_metadata.rb → mods_desc_metadata.rb} +0 -0
  27. data/{or_templates → templates}/records_controller.rb +0 -0
  28. data/{or_templates/add_tests → templates}/records_controller_spec.rb +0 -0
  29. data/{or_templates/wiring_it_into_rails → templates}/show.html.erb +0 -0
  30. data/templates/{building_a_basic_rails_app/solr.yml → solr.yml} +0 -0
  31. data/tutorial.thor +806 -341
  32. metadata +32 -30
  33. data/open-repositories-tutorial.thor +0 -888
@@ -1,493 +1,958 @@
1
- #!/usr/bin/env ruby
1
+ #! /usr/bin/env ruby
2
2
 
3
3
  require 'rubygems'
4
4
  require 'thor'
5
5
  require 'thor/group'
6
6
  require 'rails/generators/actions'
7
7
  require 'active_support/core_ext/array/extract_options'
8
+ require 'active_support/core_ext/string/inflections'
9
+ require 'fileutils'
10
+ require 'yaml'
11
+ require 'set'
8
12
 
9
- $base_templates_path = File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
13
+ # Colors used in messages to the user.
14
+ STATEMENT = Thor::Shell::Color::YELLOW
15
+ QUESTION = Thor::Shell::Color::GREEN
16
+ WAIT = Thor::Shell::Color::CYAN
17
+ WARNING = Thor::Shell::Color::RED
10
18
 
11
- class HydraTutorialApp < Thor::Group
12
- class_option :quick, :default => false
13
19
 
14
- def welcome
15
- $quick = options[:quick]
16
- say %Q{
17
- Welcome to this Hydra tutorial. We're going to go through some steps to
18
- set up a working Hydra head. We'll build the application gradually, and give you
19
- opportunities to stop and look around on the way.
20
- }, Thor::Shell::Color::YELLOW
20
+ ####
21
+ # Some utility methods used by the tutorial.
22
+ ####
21
23
 
22
- if $quick
23
- say %Q{
24
- We'll quickly build the application, give you some Hydra models, and send you on your way.
25
- }, Thor::Shell::Color::YELLOW
24
+ module HydraTutorialHelpers
26
25
 
27
- else
28
- say %Q{
29
- We'll go through this tour slowly, starting by creating a pure Rails application,
30
- and then introduce Hydra components. If you want to speed things along,
31
- }, Thor::Shell::Color::YELLOW
32
-
33
- exit unless yes? %Q{
34
- If you want to speed things along, you should quit this tutorial (by saying 'no'),
35
- and run it again with ./tutorial.thor --quick=yes.
26
+ @@conf = nil
36
27
 
37
- Do you want to continue at this pace? (y/n) }, Thor::Shell::Color::GREEN
38
- end
28
+ # Runs the Rails console for the user.
29
+ def rails_console
30
+ return if @@conf.quick
31
+ say %Q{
32
+ We'll launch the console again. Give some of those commands a try.\n}, STATEMENT
33
+ say %Q{
34
+ Hit Ctrl-D (^D) to stop the Rails console and continue this tutorial.\n}, WAIT
35
+ run "rails c"
39
36
  end
40
37
 
41
- include Thor::Actions
42
- include Rails::Generators::Actions
43
-
44
- class Prerequisites < Thor::Group
45
- class_option :quick, :default => false
46
- include Thor::Actions
47
- include Rails::Generators::Actions
38
+ # Runs the Rails server for the user, optionally
39
+ # directing their attention to a particular URL.
40
+ def rails_server url = '/'
41
+ return if @@conf.quick
42
+ say %Q{
43
+ We'll start the Rails server for you. It should be available in
44
+ your browser at:
48
45
 
49
- def install_ruby
50
- return if $quick
51
- say %Q{
52
- Obviously, if you can run this tutorial, you have already installed ruby.
53
- }, Thor::Shell::Color::YELLOW
46
+ http://localhost:3000#{url}\n}, STATEMENT
47
+ say %Q{
48
+ Hit Ctrl-C (^C) to stop the Rails server and continue this tutorial.\n}, WAIT
49
+ run "rails s"
50
+ end
54
51
 
52
+ # Offers the user a continue prompt. This is relevant only if
53
+ # the user is running all steps at once rather than one by one.
54
+ def continue_prompt
55
+ return if @@conf.quick
56
+ return unless @@conf.run_all
57
+ ask %Q{
58
+ HIT <ENTER> KEY TO CONTINUE}, WAIT
59
+ end
55
60
 
56
- ruby_executable = run 'which ruby', :capture => true
61
+ # Takes a commit message an an optional array of git commands.
62
+ # Runs either the given commands or the default commands.
63
+ def run_git(msg, *cmds)
64
+ return if @@conf.no_git
65
+ cmds = ['add -A', 'commit -m'] if cmds.size == 0
66
+ cmds.each do |cmd|
67
+ cmd += " '#{msg}'" if cmd =~ /^commit/
68
+ run "git #{cmd}", :capture => false
69
+ end
70
+ end
57
71
 
58
- say %Q{
59
- You are running this using:
60
- #{ruby_executable}
61
- }, Thor::Shell::Color::YELLOW
72
+ end
62
73
 
63
- if ruby_executable =~ /rvm/ or ruby_executable =~ /rbenv/ or ruby_executable =~ /home/ or ruby_Executable =~ /Users/
64
- say %Q{
65
- It looks like you're using rvm/rbenv/etc. (with a gemset?) We'll use this environment to build the application.
66
- }, Thor::Shell::Color::YELLOW
67
74
 
68
- else
75
+ ####
76
+ # The tutorial contains the following major components:
77
+ #
78
+ # - A couple of class methods to define the steps in the tutorial.
79
+ # Each step is a Thor task.
80
+ #
81
+ # - A main() task. This is the task invoked when the user runs
82
+ # the bin/hydra-tutorial script. It's job is to determine
83
+ # the which steps to run (either the next step in the process
84
+ # or the specific steps requested on the command line). As
85
+ # the main() task invokes those other tasks, it also persists
86
+ # information to a YAML file to keep track of the user's
87
+ # progress through the tutorial.
88
+ #
89
+ # - The other tasks: these are the steps in the tutorial, defined
90
+ # in the order that they should be run.
91
+ #
92
+ ####
93
+
94
+ class HydraTutorial < Thor
69
95
 
70
- say %Q{
71
- We checked, and it looks like you might be using a system-wide ruby. We'd like to
72
- suggest you use somethng like rvm [1], rbenv [2], etc to manage your ruby projects.
96
+ include Thor::Actions
97
+ include Rails::Generators::Actions
98
+ include HydraTutorialHelpers
73
99
 
74
- [1] http://rvm.io/
75
- [2] https://github.com/sstephenson/rbenv/
76
- }, Thor::Shell::Color::RED
100
+ # Returns an array of task names for the tasks that
101
+ # constituting the steps in the tutorial.
102
+ def self.tutorial_tasks
103
+ return tasks.keys.reject { |t| t == 'main' }
104
+ end
77
105
 
78
- exit unless yes? %Q{
79
- You can continue and hope for the best, or go install one of these ruby managers, which may make your life easier.
106
+ # Returns a set of task names for the tasks that should not
107
+ # be run inside the Rails application directory.
108
+ def self.outside_tasks
109
+ return Set.new(%w(
110
+ welcome
111
+ install_ruby
112
+ install_bundler_and_rails
113
+ new_rails_app
114
+ ))
115
+ end
80
116
 
81
- Do you want to continue anyway? (y/n)
82
- }, Thor::Shell::Color::GREEN
83
- end
117
+ # Returns array of directory paths used by Thor to find
118
+ # source files when running copy_file().
119
+ def self.source_paths
120
+ [@@conf.templates_path]
121
+ end
84
122
 
123
+ ####
124
+ # The main task that is invoked by the gem's executable script.
125
+ #
126
+ # This task invokes either the next task in the tutorial or
127
+ # the task(s) explicitly requested by the user.
128
+ ####
129
+
130
+ # Define a Struct that we will use hold some global values we need.
131
+ # An instance of this Struct will be kept in @@conf.
132
+ HTConf = Struct.new(
133
+ # Command-line options.
134
+ :run_all, # If true, run all remaining tasks rather than only the next task.
135
+ :quick, # If true, bypass interactive user confirmations.
136
+ :reset, # If true, reset the tutorial back to the beginning.
137
+ :gems_from_git, # If true, get a couple of gems directly from github.
138
+ :debug_steps, # If true, just print task names rather than running tasks.
139
+ :no_git, # If true, do not create Git commits as the Rails app is modified.
140
+ :diff, # If true, run git diff: previous vs. current code.
141
+ :app, # Name of the Rails application's subdirectory.
142
+
143
+ # Other config.
144
+ :progress_file, # Name of YAML file used to keep track of finished steps.
145
+ :done, # Array of tasks that have been completed already.
146
+ :templates_path # Directory where Thor can file source files for copy_file().
147
+ )
148
+
149
+ # Command-line options for the main() method.
150
+ desc('main: FIX', 'FIX')
151
+ method_options(
152
+ :run_all => :boolean,
153
+ :quick => :boolean,
154
+ :reset => :boolean,
155
+ :gems_from_git => :boolean,
156
+ :debug_steps => :boolean,
157
+ :no_git => :boolean,
158
+ :diff => :boolean,
159
+ :app => :string
160
+ )
161
+
162
+ def main(*requested_tasks)
163
+ # Setup.
164
+ HydraTutorial.initialize_config(options)
165
+ HydraTutorial.initialize_progress_file
166
+ HydraTutorial.load_progress_info
167
+ ts = HydraTutorial.determine_tasks_to_run(requested_tasks)
168
+ outside = HydraTutorial.outside_tasks
169
+
170
+ # If user requests --diff, just run git diff and exit.
171
+ if @@conf.diff
172
+ inside(@@conf.app) { run 'git diff HEAD^1..HEAD' }
173
+ exit
85
174
  end
86
175
 
87
- def install_bundler_and_rails
88
- say %Q{
89
- We're going to install some prerequisite gems in order to create our skeleton Rails application.
90
- }, Thor::Shell::Color::YELLOW
91
- run 'gem install bundler rails'
176
+ # Run tasks.
177
+ ts.each do |t|
178
+ # Either print the task that would be run (in debug mode) or run the task.
179
+ if @@conf.debug_steps
180
+ say "Running: task=#{t.inspect}", STATEMENT
181
+ else
182
+ # A few of the initial tasks run outside the Rails app directory,
183
+ # but most run inside the app directory.
184
+ if outside.include?(t)
185
+ invoke(t, [], {})
186
+ else
187
+ inside(@@conf.app) { invoke(t, [], {}) }
188
+ end
189
+ end
190
+ # Persist the fact that the task was run to the YAML progress file.
191
+ @@conf.done << t
192
+ File.open(@@conf.progress_file, "w") { |f| f.puts(@@conf.to_yaml) }
92
193
  end
93
194
 
94
- def new_rails_app
95
- say %Q{
96
- Now we'll create the application.
97
- }, Thor::Shell::Color::YELLOW
98
- run 'rails new hydra_tutorial_app'
99
- run 'cd hydra_tutorial_app'
100
-
195
+ # Inform user if the tutorial is finished.
196
+ if ts.size == 0
197
+ msg = "All tasks have been completed. Use the --reset option to start over."
198
+ say(msg, WARNING)
101
199
  end
102
200
 
103
- def out_of_the_box
104
- return if $quick
105
- say %Q{
106
- Here's a chance to look around. You can see the structure of a Rails application.
107
- ./app
108
- ./config
109
- ./lib
110
- Gemfile
111
- }
112
-
113
- ask %Q{
114
-
115
- Hit ENTER when you're ready to continue.
116
- }, Thor::Shell::Color::GREEN
117
- end
201
+ # In debug mode, we print the contents of the progress file.
202
+ run("cat #{@@conf.progress_file}", :verbose => false) if @@conf.debug_steps
203
+ end
118
204
 
119
- # and then clean up some cruft
120
- def remove_public_index
121
- say %Q{
122
- We'll now remove the Rails directions from the application.
123
- }, Thor::Shell::Color::YELLOW
124
- inside 'hydra_tutorial_app' do
125
- remove_file 'public/index.html'
126
- end
127
- end
205
+ # Sets up configuration information in the @@conf variable.
206
+ def self.initialize_config(opts)
207
+ @@conf = HTConf.new
208
+ @@conf.run_all = opts[:run_all]
209
+ @@conf.quick = opts[:quick]
210
+ @@conf.reset = opts[:reset]
211
+ @@conf.gems_from_git = opts[:gems_from_git]
212
+ @@conf.debug_steps = opts[:debug_steps]
213
+ @@conf.no_git = opts[:no_git]
214
+ @@conf.diff = opts[:diff]
215
+ @@conf.app = (opts[:app] || 'hydra_tutorial_app').strip.parameterize('_')
216
+ @@conf.progress_file = (opts[:progress_file] || '.hydra-tutorial-progress')
217
+ @@conf.done = nil
218
+ @@conf.templates_path = File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
128
219
  end
129
220
 
130
- class BuildingABasicRailsApp < Thor::Group
131
- include Thor::Actions
132
- include Rails::Generators::Actions
221
+ # Initializes the YAML progress file that keeps track of which
222
+ # tutorial tasks have been completed. This needs to occur if
223
+ # the YAML file does not exist yet or if the user requested a reset.
224
+ # In the latter case, the program exits immediately.
225
+ def self.initialize_progress_file
226
+ return if (File.file?(@@conf.progress_file) and ! @@conf.reset)
227
+ File.open(@@conf.progress_file, "w") { |f|
228
+ f.puts("---\n") # Empty YAML file.
229
+ }
230
+ exit if @@conf.reset
231
+ end
133
232
 
134
- def self.source_paths
135
- [File.join($base_templates_path, "building_a_basic_rails_app")]
136
- end
233
+ # Loads the progress info from the YAML file, and
234
+ # sets the corresponding @@conf.done value.
235
+ def self.load_progress_info
236
+ h = YAML.load_file(@@conf.progress_file) || {}
237
+ @@conf.done = (h[:done] || [])
238
+ end
137
239
 
138
- def notes
139
- say %Q{
140
- We're going to build an application to track (simplified) datasets and their metadata.
141
- }, Thor::Shell::Color::YELLOW
240
+ # Takes an array of task names: those requested on the command line
241
+ # by the user (typically this list is empty).
242
+ # Returns an arrray of task names: those that the main() taks will invoke.
243
+ def self.determine_tasks_to_run(requested_tasks)
244
+ if requested_tasks.size == 0
245
+ # User did not request any tasks, so we determine which tasks
246
+ # have not been done yet. We either return all of those tasks
247
+ # or, more commonly, just the next text.
248
+ done = Set.new(@@conf.done)
249
+ ts = tutorial_tasks.reject { |t| done.include?(t) }
250
+ ts = [ts.first] unless (@@conf.run_all or ts == [])
251
+ return ts
252
+ else
253
+ # User requested particular tasks, so we will simply return
254
+ # them, provided that they are valid task names.
255
+ valid = Set.new(tutorial_tasks)
256
+ requested_tasks.each { |rt|
257
+ abort "Invalid task name: #{rt}." unless valid.include?(rt)
258
+ }
259
+ return requested_tasks
142
260
  end
261
+ end
143
262
 
144
- def as_if_this_was_just_a_rails_applications
145
- say %Q{
146
- If we wanted to build a Rails application to do this, we would add some models and controllers.
147
263
 
148
- Rails can help "scaffold" the application for us.
149
- }, Thor::Shell::Color::YELLOW
264
+ ####
265
+ # The remaining methods represent the steps in the tutorial.
266
+ # The tasks should be defined in the order they should run.
267
+ ####
150
268
 
151
- generate 'scaffold', 'dataset', 'title', 'author', 'url', 'description:text'
152
- rake 'db:migrate'
269
+ desc('welcome: FIX', 'FIX')
270
+ def welcome
271
+ say %Q{
272
+ Welcome to this Hydra tutorial. We're going to step through building a
273
+ working Hydra application. We'll build the application gradually, starting
274
+ by building our "business logic", wiring in HTML views, and then
275
+ connecting it to our Rails application.
153
276
 
154
- say %Q{
155
- This created a Dataset model (in ./app/models/dataset.rb), a controller, and some views.
156
- }, Thor::Shell::Color::YELLOW
277
+ At several points in this tutorial, as we iteratively develop our files,
278
+ you may be prompted to review conflicts between versions of files. It is
279
+ safe to blindly accept the changes ('y'), however you may wish to view
280
+ the diff ('d') to see the things we're change.
157
281
 
158
- ask %Q{
159
- Take a look around. Hit ENTER when you're ready to continue.
160
- }, Thor::Shell::Color::GREEN
161
- end
282
+ This tutorial, a README file, and our bug tracker are at:
162
283
 
163
- def but_maybe_we_want_to_store_our_metadata_as_xml
164
- say %Q{
165
- But it turns out a relational database is not a great place to store complex metadata objects,
166
- with nesting, hierarchy, repetition, etc like we often fine in the digital library world. We'd
167
- also like to store and manage our data in an exchangeable form rather than a custom-built database.
284
+ https://github.com/projecthydra/hydra-tutorial
168
285
 
169
- In our world, we often find ourselves dealing with XML-based metadata. Fortunately, we have a gem called 'om' that can help us deal with XML metadata.
170
- To start using it, we need to add it to our Gemfile.
171
- }, Thor::Shell::Color::YELLOW
286
+ We'll generate a stub application in the #{@@conf.app}
287
+ folder. You can change that using the --app option.\n}, STATEMENT
288
+ end
172
289
 
173
- gem 'om'
174
- run 'bundle install'
290
+ desc('install_ruby: FIX', 'FIX')
291
+ def install_ruby
292
+ return if @@conf.quick
293
+ say %Q{
294
+ Obviously, if you can run this tutorial, you have already installed ruby.
295
+ }, STATEMENT
175
296
 
176
- say %Q{
177
- Now let's adapt our Dataset model to use OM. First we'll add some code that allows us to persist our
178
- OM Documents on the filesystem (in db/datasets) and then add a simple OM terminology as a drop-in
179
- replacement for the ActiveRecord scaffold object.
297
+ ruby_executable = run 'which ruby', :capture => true, :verbose => false
298
+ ruby_executable.strip!
180
299
 
181
- }, Thor::Shell::Color::YELLOW
300
+ say %Q{
301
+ You are running this using:
182
302
 
183
- run "mkdir db/datasets"
184
- copy_file "om_record.rb", "app/models/om_record.rb"
303
+ #{ruby_executable}}, STATEMENT
185
304
 
305
+ if ruby_executable =~ /rvm/ or ruby_executable =~ /rbenv/ or ruby_executable =~ /home/ or ruby_executable =~ /Users/
186
306
  say %Q{
187
- Press 'd' to see the difference between the Rails version and the OM version of Dataset.
188
- }, Thor::Shell::Color::YELLOW
189
-
190
- copy_file "dataset_simple_om.rb", "app/models/dataset.rb"
307
+ It looks like you're using rvm/rbenv/etc. We'll use
308
+ this environment to build the application.\n}, STATEMENT
309
+ else
310
+ say %Q{
311
+ We checked, and it looks like you might be using a system-wide ruby.
312
+ We suggest you use somethng like rvm [1], rbenv [2], etc to manage
313
+ your ruby projects.
191
314
 
192
- ask %Q{
193
- Take a look around.
315
+ You can continue and hope for the best, or go install one of these
316
+ ruby managers, which may make your life easier.
194
317
 
195
- Hit ENTER when you're ready to continue.
196
- }, Thor::Shell::Color::GREEN
318
+ [1] http://rvm.io/
319
+ [2] https://github.com/sstephenson/rbenv/\n}, WARNING
197
320
 
321
+ continue_prompt
198
322
  end
323
+ end
324
+
325
+ desc('install_bundler_and_rails: FIX', 'FIX')
326
+ def install_bundler_and_rails
327
+ say %Q{
328
+ We're going to install some prerequisite gems in order to create our
329
+ skeleton Rails application.\n}, STATEMENT
330
+ run 'gem install bundler rails', :capture => false
331
+ end
199
332
 
333
+ desc('new_rails_app: FIX', 'FIX')
334
+ def new_rails_app
335
+ say %Q{
336
+ Now we'll create the application.\n}, STATEMENT
200
337
 
201
- def stop_using_the_filesystem
338
+ if File.exists? @@conf.app
202
339
  say %Q{
203
- Storing the documents on the filesystem has worked so far, but what if we wanted to start
204
- managing whole objects (instead of XML documents), version datastream, keep checksums...
340
+ #{@@conf.app} already exists. Either remove it or provide
341
+ a different application name using the --app option.}, WARNING
342
+ exit
343
+ end
205
344
 
206
- We use Fedora [3], and ActiveFedora to work with data in our repository. We also use Solr to
207
- index and provide searching, faceting, etc for our content. For now, you can just concentrate on
208
- Fedora. We'll have a section on Solr and discovery interfaces later.
345
+ run "rails new #{@@conf.app}", :capture => false
346
+ end
209
347
 
210
- [3] http://fedora-commons.org
211
- }, Thor::Shell::Color::YELLOW
348
+ desc('git_initial_commit: FIX', 'FIX')
349
+ def git_initial_commit
350
+ say %Q{
351
+ We will keep track of our work using Git so that you can see how
352
+ the files in the project change from one step to the next. To see
353
+ the difference you can open a terminal in the Rails application
354
+ directory and run the following Git command.
212
355
 
213
- say %Q{
214
- Fedora runs as a java servlet inside a container like Tomcat or Jetty. Hydra provides a bundled
215
- version of Fedora and Solr for testing and development.
216
- }, Thor::Shell::Color::YELLOW
356
+ git diff HEAD^1..HEAD
217
357
 
218
- say %Q{
219
- We'll download a copy now. It may take awhile.
220
- }, Thor::Shell::Color::YELLOW
221
- unless File.exists? '../jetty'
222
- git :clone => 'git://github.com/projecthydra/hydra-jetty.git ../jetty'
223
- end
224
- run 'cp -R ../jetty jetty'
225
- # run 'rake hydra:jetty:config'
358
+ Or you can simply run the tutorial with the --diff option.
226
359
 
227
- say %Q{
228
- Now we're configure it and start the application.
229
- }, Thor::Shell::Color::YELLOW
230
- rake 'hydra:jetty:config'
360
+ Alternatively, you can use a tool like Gitx to see the differences
361
+ in the code from one step in the tutorial to the next.
362
+
363
+ First, we'll initialize our project's Git repository.\n\n}, STATEMENT
364
+ run_git('', 'init')
365
+ run_git('Initial commit')
366
+ end
231
367
 
232
- copy_file 'solr.yml', 'config/solr.yml'
233
- copy_file 'fedora.yml', 'config/fedora.yml'
368
+ desc('out_of_the_box: FIX', 'FIX')
369
+ def out_of_the_box
370
+ say %Q{
371
+ Here's a chance to look around. You can see the structure of
372
+ a Rails application. In particular, look at:
373
+ ./app
374
+ ./config
375
+ ./lib
376
+ Gemfile
377
+
378
+ If we launched the Rails application server, we can see the application
379
+ running in the browser and you can see if everything is working.\n}, STATEMENT
380
+ rails_server
381
+ end
234
382
 
235
- say %Q{
236
- And we'll use jettywrapper to help start and stop the service.
237
- }, Thor::Shell::Color::YELLOW
383
+ desc('adding_dependencies: FIX', 'FIX')
384
+ def adding_dependencies
385
+ gem 'execjs'
386
+ gem 'therubyracer'
387
+ run_git('Added gems for Javascript: execjs and therubyracer')
388
+ end
238
389
 
239
- gem 'jettywrapper'
240
- run 'bundle install'
241
- rake 'jetty:start'
390
+ desc('add_fedora_and_solr_with_hydrajetty: FIX', 'FIX')
391
+ def add_fedora_and_solr_with_hydrajetty
392
+ say %Q{
393
+ Fedora runs as a Java servlet inside a container like Tomcat or Jetty.
394
+ Hydra provides a bundled version of Fedora and Solr for
395
+ testing and development.\n}, STATEMENT
396
+
397
+ say %Q{
398
+ We'll download it now and put a copy into your application's directory.
399
+ This might take awhile.\n}, STATEMENT
400
+ unless File.exists? '../jetty'
401
+ git :clone => '-b 4.x git://github.com/projecthydra/hydra-jetty.git ../jetty'
402
+ end
403
+ unless File.exists? 'jetty'
404
+ run 'cp -R ../jetty jetty'
405
+ end
406
+ append_to_file '.gitignore', "\njetty\n"
407
+ run_git('Added jetty to project and git-ignored it')
408
+ end
242
409
 
243
- say %Q{
244
- Take a look around. Jetty should be running on port 8983. You can see the Fedora server at
410
+ desc('jetty_configuration: FIX', 'FIX')
411
+ def jetty_configuration
412
+ say %Q{
413
+ We'll add some configuration yml files with information to connect
414
+ to Solr and Fedora.\n\n}, STATEMENT
245
415
 
246
- http://localhost:8983/fedora/
416
+ copy_file 'solr.yml', 'config/solr.yml'
417
+ copy_file 'fedora.yml', 'config/fedora.yml'
247
418
 
248
- And a Solr index at
419
+ say %Q{
420
+ Add the 'jettywrapper' gem, which adds Rake tasks to start and stop Jetty.\n}, STATEMENT
249
421
 
250
- http://localhost:8983/solr/development/admin/
251
- }, Thor::Shell::Color::YELLOW
422
+ gem 'jettywrapper'
423
+ run 'bundle install', :capture => false
424
+ run_git('Solr and Fedora configuration')
252
425
 
253
- ask %Q{
254
- Hit ENTER when you're ready to continue.
255
- }, Thor::Shell::Color::GREEN
426
+ say %Q{
427
+ Starting Jetty\n}, STATEMENT
428
+ rake 'jetty:start'
256
429
 
257
- end
430
+ say %Q{
431
+ Take a look around. Jetty should be running on port 8983. You can see
432
+ the Fedora server at:
258
433
 
259
- def convert_our_model_to_activefedora
260
- say %Q{
261
- We'll update our Dataset object to use ActiveFedora.
262
- }, Thor::Shell::Color::YELLOW
434
+ http://localhost:8983/fedora/
263
435
 
264
- gem 'active-fedora'
265
- run 'bundle install'
266
- copy_file "dataset_af_om.rb", "app/models/dataset.rb"
436
+ And a Solr index at:
267
437
 
268
- say %Q{
269
- You should be able to create new dataset objects and see them updated in Fedora.
270
- }, Thor::Shell::Color::YELLOW
438
+ http://localhost:8983/solr/development/admin/\n}, STATEMENT
271
439
 
272
- ask %Q{
273
- Hit ENTER when you're ready to continue.
274
- }, Thor::Shell::Color::GREEN
275
- end
440
+ continue_prompt
276
441
  end
277
442
 
278
- class Application < Thor::Group
279
- include Thor::Actions
280
- include Rails::Generators::Actions
443
+ desc('remove_public_index: FIX', 'FIX')
444
+ def remove_public_index
445
+ remove_file 'public/index.html'
446
+ run_git('Removed the Rails index.html file')
447
+ end
281
448
 
282
- def self.source_paths
283
- [File.join($base_templates_path, "application")]
284
- end
449
+ desc('add_activefedora: FIX', 'FIX')
450
+ def add_activefedora
451
+ say %Q{
452
+ The active-fedora gem provides a way to model Fedora objects within Ruby.
453
+ It will help you create Ruby models for creating, updating and reading
454
+ objects from Fedora using a domain-specific language (DSL) similar
455
+ to the Rails' ActiveRecord.
456
+
457
+ The om gem provides mechanisms for mapping XML documents into Ruby.
458
+
459
+ We'll add both of these to the Gemfile.\n\n}, STATEMENT
460
+ gem 'active-fedora'
461
+ gem 'om'
462
+ run 'bundle install', :capture => false
463
+ run_git('Added gems: active-fedora and om')
464
+ end
285
465
 
286
- # here are some gems that help
287
- def add_blacklight_and_hydra
288
- say %Q{
289
- Eventually, common patterns get packaged up into new gems.
290
- }, Thor::Shell::Color::YELLOW
466
+ desc('add_initial_model: FIX', 'FIX')
467
+ def add_initial_model
468
+ say %Q{
469
+ Now we'll add a basic ActiveFedora stub model for a 'Record'.\n\n}, STATEMENT
470
+ copy_file "basic_af_model.rb", "app/models/record.rb"
471
+ run_git('Created a minimal Record model')
472
+ end
291
473
 
292
- say %Q{
293
- We use blacklight to provide a search interface.
294
- }, Thor::Shell::Color::YELLOW
474
+ desc('rails_console_tour: FIX', 'FIX')
475
+ def rails_console_tour
476
+ say %Q{
477
+ Now we'll give you a chance to look at the Record model. If you
478
+ launch the Rails interactive console (`rails c`), we can create
479
+ and manipulate our object:
480
+
481
+ ## CREATE
482
+ > obj = Record.new
483
+ # => #<Record:1571331701243443635 @pid="__DO_NOT_USE__" >
484
+ > obj.descMetadata.content = e.g. '<my_xml_content />'
485
+ > obj.save
486
+
487
+ > obj.pid
488
+ # => e.g. 'changeme:1'
489
+
490
+ ## RETRIEVE
491
+ > obj = Record.find('changeme:1')
492
+ > ds = obj.descMetadata
493
+ # => #<ActiveFedora::NokogiriDatastream:3283711306477137919 ...>
494
+ > ds.content
495
+ # => (should be the XML document you added before)
496
+
497
+ ## UPDATE
498
+ # manipulating XML:
499
+ > ds.ng_xml.xpath('//my_xml_content')
500
+
501
+ ## DELETE
502
+ > obj.delete\n}, STATEMENT
503
+ rails_console
504
+ end
295
505
 
296
- gem 'blacklight'
297
- run 'bundle install'
298
- generate 'blacklight', '--devise'
506
+ desc('enhance_model_with_om_descmd: FIX', 'FIX')
507
+ def enhance_model_with_om_descmd
508
+ say %Q{
509
+ Instead of working with the Nokogiri XML document directly, we
510
+ can use OM to make querying an XML document easier. We'll replace the
511
+ previous Record with a OM-enabled document.\n\n}, STATEMENT
512
+ f = "app/models/record.rb"
513
+ remove_file f
514
+ copy_file "basic_om_model.rb", f
515
+ run_git('Set up basic OM descMetadata for Record model')
516
+ end
299
517
 
300
- say %Q{
301
- And hydra-head bundles OM, ActiveFedora, etc for us. It also includes things like
302
- gated discovery and permissions (through hydra-access-controls).
303
- }, Thor::Shell::Color::YELLOW
518
+ desc('experiment_with_om_descmd: FIX', 'FIX')
519
+ def experiment_with_om_descmd
520
+ say %Q{
521
+ If you launch the Rails interactive console, we can now create and
522
+ manipulate our object using methods provided by OM.
523
+
524
+ > obj = Record.new
525
+ > obj.descMetadata.title = "My object title"
526
+ > obj.save
527
+ > obj.descMetadata.content
528
+ # => An XML document with the title "My object title"\n}, STATEMENT
529
+ rails_console
530
+ end
304
531
 
305
- gem 'hydra-head', "~> 4.1"
306
- run 'bundle install'
307
- generate 'hydra:head', 'User'
532
+ desc('use_the_delegate_method: FIX', 'FIX')
533
+ def use_the_delegate_method
534
+ say %Q{
535
+ We can use the #delegate method to tell the model-object how
536
+ to access these attributes.
537
+
538
+ > obj = Record.new
539
+ > obj.title = "My object title"
540
+ > obj.save
541
+ > obj.descMetadata.content
542
+ # => An XML document with the title "My object title"\n\n}, STATEMENT
543
+
544
+ loc = 'has_metadata :name => "descMetadata", :type => DatastreamMetadata\n'
545
+ insert_into_file "app/models/record.rb", :after => loc do
546
+ "delegate :title, :to => 'descMetadata'\n"
308
547
  end
548
+ run_git('Modify Record model to delegate title to descMetadata')
549
+ end
309
550
 
310
- def rake_db_migrate
311
- rake 'db:migrate'
312
- rake 'db:test:prepare'
313
- end
551
+ desc('add_mods_model_with_mods_descmd: FIX', 'FIX')
552
+ def add_mods_model_with_mods_descmd
553
+ say %Q{
554
+ We'll now replace the minimal XML metadata schema with a simple
555
+ MODS-based example, using an OM terminology we prepared earlier.
314
556
 
315
- def install_hydra_jetty
316
- if $quick # if we were in quick mode, we skipped this step from before..
317
- say %Q{
318
- Fedora runs as a java servlet inside a container like Tomcat or Jetty. Hydra provides a bundled
319
- version of Fedora and Solr for testing and development.
320
- }, Thor::Shell::Color::YELLOW
557
+ We'll put the MODS datastream in a separate module and file, so that
558
+ it can be easily reused in other ActiveFedora-based objects.\n}, STATEMENT
321
559
 
322
- say %Q{
323
- We'll download a copy now. It may take awhile.
324
- }, Thor::Shell::Color::YELLOW
560
+ f = "app/models/record.rb"
561
+ remove_file f
562
+ copy_file "basic_mods_model.rb", f
563
+ copy_file "mods_desc_metadata.rb", "app/models/mods_desc_metadata.rb"
564
+ run_git('Set up MODS descMetadata')
565
+ end
325
566
 
326
- unless File.exists? '../jetty'
327
- git :clone => 'git://github.com/projecthydra/hydra-jetty.git ../jetty'
328
- end
329
- run 'cp -R ../jetty jetty'
567
+ desc('experiment_with_mods_descmd: FIX', 'FIX')
568
+ def experiment_with_mods_descmd
569
+ say %Q{
570
+ If you launch the Rails interactive console, we can now create
571
+ and manipulate our object using methods provided by OM.
572
+
573
+ > obj = Record.new
574
+ > obj.title = "My object title"
575
+ > obj.save
576
+ > obj.descMetadata.content
577
+ # => A MODS XML document\n}, STATEMENT
578
+ rails_console
579
+ end
330
580
 
331
- rake 'hydra:jetty:config'
581
+ desc('record_generator: FIX', 'FIX')
582
+ def record_generator
583
+ say %Q{
584
+ Now that we've set up our model and successfully added content
585
+ into Fedora, now we want to connect the model to a Rails web application.
332
586
 
333
- gem 'jettywrapper'
334
- run 'bundle install'
335
- rake 'jetty:start'
336
- else
587
+ We'll start by using the standard Rails generators to create
588
+ a scaffold controller and views, which will give us a
589
+ place to start working.\n\n}, STATEMENT
337
590
 
338
- rake 'jetty:stop'
339
- rake 'hydra:jetty:config'
340
- rake 'jetty:start'
341
- end
591
+ generate "scaffold_controller Record --no-helper --skip-test-framework"
592
+ route "resources :records"
593
+ run_git('Used Rails generator to create controller and views for the Record model')
342
594
 
343
- end
595
+ say %Q{
596
+ If you look in ./app/views/records, you can see a set of
597
+ Rails ERB templates.
344
598
 
345
- def fixup_ui
346
- remove_file 'app/assets/stylesheets/datasets.css.scss'
347
- remove_file 'app/assets/stylesheets/scaffolds.css.scss'
599
+ ./app/controlers/records_controller.rb contains the controller
600
+ that ties the model to the views.\n}, STATEMENT
601
+
602
+ continue_prompt
603
+ end
604
+
605
+ desc('add_new_form: FIX', 'FIX')
606
+ def add_new_form
607
+ say %Q{
608
+ The scaffold just provided the basic outline for an application, so
609
+ we need to provide the guts for the web form. Here's a simple one:\n\n}, STATEMENT
610
+ files = [
611
+ ["_form.wiring_it_into_rails.html.erb", "app/views/records/_form.html.erb"],
612
+ ["show.html.erb", "app/views/records/show.html.erb"],
613
+ ]
614
+ files.each do |src, dst|
615
+ remove_file dst
616
+ copy_file src, dst
348
617
  end
618
+ run_git('Fleshed out the edit form and show page')
619
+ end
349
620
 
350
- def fixup_datasets
351
- return if $quick
352
- say %Q{
353
- We need to make a couple of tweaks to our Dataset model and controller in order
354
- to make it a Hydra-compliant object.
621
+ desc('check_the_new_form: FIX', 'FIX')
622
+ def check_the_new_form
623
+ say %Q{
624
+ If we start the Rails server, we should now be able to visit the records
625
+ in the browser, create new records, and edit existing records.
355
626
 
356
- Because Hydra enforces access controls in the discovery layer (and, by default, no one
357
- has access), we need to teach our model and controller about the Hydra rightsMetadata model
358
- and have the controller tell the object who deposited it.
359
- }, Thor::Shell::Color::YELLOW
627
+ Start by creating a new record:\n}, STATEMENT
628
+ rails_server '/records/new'
629
+ end
360
630
 
361
- copy_file "dataset_hydra_om.rb", "app/models/dataset.rb"
631
+ desc('add_hydra_gems: FIX', 'FIX')
632
+ def add_hydra_gems
633
+ say %Q{
634
+ Thus far, we've been using component parts of the Hydra framework, but
635
+ now we'll add in the whole framework so we can take advantage of common
636
+ patterns that have emerged in the Hydra community, including search,
637
+ gated discovery, etc.
362
638
 
363
- inject_into_class "app/controllers/datasets_controller.rb", 'DatasetsController' do
364
- " include Hydra::AssetsControllerHelper\n"
365
- end
639
+ We'll add a few new gems:
366
640
 
367
- insert_into_file "app/controllers/datasets_controller.rb", :after => "@dataset = Dataset.new(params[:dataset])\n" do
368
- " apply_depositor_metadata(@dataset)\n"
369
- end
370
- end
641
+ - blacklight provides a discovery interface on top of the Solr index
371
642
 
372
- def lets_make_a_better_terminology
373
- say %Q{
374
- So far, we've been working with a made-up XML schema, however, in the real world, we're probably
375
- dealing with more complex data in well-known standards like MODS.
643
+ - hydra-head provides a number of common Hydra patterns
644
+
645
+ - devise is a standard Ruby gem for providing user-related
646
+ functions, like registration, sign-in, etc.\n\n}, STATEMENT
376
647
 
377
- Now we'll replace our custom schema with a basic MODS schema.
378
- }, Thor::Shell::Color::YELLOW
379
- copy_file "mods_desc_metadata.rb", "app/models/mods_desc_metadata.rb"
380
- copy_file "dataset_hydra_mods_om.rb", "app/models/dataset.rb"
648
+ if @@conf.gems_from_git
649
+ gem 'blacklight', :git => "git://github.com/projectblacklight/blacklight.git"
650
+ gem 'hydra-head', :git => "git://github.com/projecthydra/hydra-head.git"
651
+ else
652
+ gem 'blacklight'
653
+ gem 'hydra-head', ">= 4.1.1"
381
654
  end
655
+ gem 'devise'
656
+ run 'bundle install', :capture => false
657
+ run_git('Added gems: blacklight, hydra-head, devise')
658
+ end
382
659
 
660
+ desc('run_hydra_generators: FIX', 'FIX')
661
+ def run_hydra_generators
662
+ say %Q{
663
+ These gems provide generators for adding basic views, styles, and override
664
+ points into your application. We'll run these generators now.\n}, STATEMENT
665
+ f = 'config/solr.yml'
666
+ remove_file f
667
+ generate 'blacklight', '--devise'
668
+ remove_file f
669
+ remove_file 'app/controllers/catalog_controller.rb'
670
+ generate 'hydra:head', 'User'
671
+ run_git('Ran blacklight and hydra-head generators')
383
672
  end
384
673
 
385
- class MakeItNice < Thor::Group
386
- include Thor::Actions
387
- include Rails::Generators::Actions
674
+ desc('db_migrate: FIX', 'FIX')
675
+ def db_migrate
676
+ say %Q{
677
+ Blacklight uses a SQL database for keeping track of user bookmarks,
678
+ searches, etc. We'll run the migrations next:\n\n}, STATEMENT
679
+ rake 'db:migrate'
680
+ rake 'db:test:prepare'
681
+ run_git('Ran db:migrate, which created db/schema.rb')
682
+ end
388
683
 
389
- def self.source_paths
390
- [File.join($base_templates_path, "make_it_nice")]
391
- end
684
+ desc('hydra_jetty_config: FIX', 'FIX')
685
+ def hydra_jetty_config
686
+ say %Q{
687
+ Hydra provides some configuration for Solr and Fedora. Use them.\n}, STATEMENT
688
+ rake 'jetty:stop'
689
+ rake 'hydra:jetty:config'
690
+ rake 'jetty:start'
691
+ end
392
692
 
393
- # now we want our app to do stuff.. so lets enhance our old models
693
+ desc('add_access_rights: FIX', 'FIX')
694
+ def add_access_rights
695
+ say %Q{
696
+ We need to make a couple changes to our controller and model to make
697
+ them fully-compliant objects by teaching them about access rights.
394
698
 
395
- def some_better_views
699
+ We'll also update our controller to provide access controls on records.\n\n}, STATEMENT
396
700
 
701
+ inject_into_class "app/controllers/records_controller.rb", 'RecordsController' do
702
+ " include Hydra::AssetsControllerHelper\n"
397
703
  end
398
704
 
399
- def file_uploads
705
+ insert_into_file "app/controllers/records_controller.rb", :after => "@record = Record.new(params[:record])\n" do
706
+ " apply_depositor_metadata(@record)\n"
707
+ end
400
708
 
709
+ inject_into_class "app/models/record.rb", "Record" do
710
+ "
711
+ include Hydra::ModelMixins::CommonMetadata
712
+ include Hydra::ModelMethods
713
+ "
401
714
  end
402
715
 
716
+ insert_into_file "app/models/solr_document.rb", :after => "include Blacklight::Solr::Document\n" do
717
+ "
718
+ include Hydra::Solr::Document
719
+ "
720
+ end
403
721
 
404
- def sprinkle_some_css
722
+ insert_into_file "app/assets/javascripts/application.js", :after => "//= require_tree .\n" do
723
+ "Blacklight.do_search_context_behavior = function() { }\n"
724
+ end
405
725
 
726
+ inject_into_class "app/controllers/records_controller.rb", 'RecordsController' do
727
+ " include Hydra::AccessControlsEnforcement\n" +
728
+ " before_filter :enforce_access_controls\n"
406
729
  end
407
730
 
731
+ run_git('Modify controller and model to include access rights')
408
732
  end
409
733
 
410
- class Tests < Thor::Group
411
- include Thor::Actions
412
- include Rails::Generators::Actions
734
+ desc('check_catalog: FIX', 'FIX')
735
+ def check_catalog
736
+ say %Q{
737
+ Blacklight and Hydra-Head have added some new functionality to the
738
+ application. We can now look at a search interface (provided
739
+ by Blacklight) and use gated discovery over our repository. By default,
740
+ objects are only visible to their creator.
413
741
 
414
- # and write some tests
742
+ Create some new objects, and then check out the search catalog at:
415
743
 
416
- end
744
+ http://localhost:3000/catalog\n}, STATEMENT
417
745
 
418
- class InitialSteps < Thor::Group
419
- include Thor::Actions
420
- include Rails::Generators::Actions
746
+ # TODO: remove this monkey-patch fixing a bug in hydra-head.
747
+ f = `bundle show hydra-head`
748
+ f = "#{f.strip}/app/views/_user_util_links.html.erb"
749
+ gsub_file f, /.+folder_index_path.+/, ''
421
750
 
422
- # here are some steps you can do to get started
423
- def create_a_user_account
751
+ rails_server('/records/new')
752
+ end
424
753
 
754
+ desc('install_rspec: FIX', 'FIX')
755
+ def install_rspec
756
+ say %Q{
757
+ One of the great things about the Rails framework is the strong
758
+ testing ethic. We'll use rspec to write a couple tests for
759
+ this application.\n\n}, STATEMENT
760
+ gem_group :development, :test do
761
+ gem 'rspec'
762
+ gem 'rspec-rails'
425
763
  end
764
+ run 'bundle install', :capture => false
765
+ generate 'rspec:install'
766
+ run_git('Added rspec to project')
767
+ end
426
768
 
427
- def explore_the_application
428
- run 'rails s'
769
+ # TODO: write the test.
770
+ desc('write_model_test: FIX', 'FIX')
771
+ def write_model_test
772
+ # copy_file 'record_test.rb', 'spec/models/record_test.rb'
773
+ # run_git('Added a model test')
774
+ run 'rspec'
775
+ end
429
776
 
430
- end
777
+ # TODO: this test should do something.
778
+ desc('write_controller_test: FIX', 'FIX')
779
+ def write_controller_test
780
+ say %Q{
781
+ Here's a quick example of a test.\n\n}
782
+ copy_file 'records_controller_spec.rb', 'spec/controllers/records_controller_spec.rb'
783
+ run_git('Added a controller test')
784
+ run 'rspec'
431
785
  end
432
786
 
433
-
434
- class Cleanup < Thor::Group
435
- include Thor::Actions
436
- include Rails::Generators::Actions
437
-
438
- # and write some tests
439
- #
440
- def stop_jetty
441
- rake 'jetty:stop'
787
+ desc('install_capybara: FIX', 'FIX')
788
+ def install_capybara
789
+ say %Q{
790
+ We also want to write integration tests to test the end-result that
791
+ a user may see. We'll add the capybara gem to do that.\n\n}, STATEMENT
792
+ gem_group :development, :test do
793
+ gem 'capybara'
442
794
  end
795
+ run 'bundle install', :cature => true
796
+ run_git('Added capybara gem')
797
+ end
798
+
799
+ desc('write_integration_test: FIX', 'FIX')
800
+ def write_integration_test
801
+ say %Q{
802
+ Here's a quick integration test that proves deposit works.\n}, STATEMENT
803
+ copy_file 'integration_spec.rb', 'spec/integration/integration_spec.rb'
804
+ run_git('Added an integration test')
805
+ end
443
806
 
807
+ desc('run_integration_test_fail: FIX', 'FIX')
808
+ def run_integration_test_fail
809
+ say %Q{
810
+ Now that the integration spec is in place, when we try to run rspec,
811
+ we'll get a test failure because it can't connect to Fedora.\n}, STATEMENT
812
+ run 'rspec'
444
813
  end
445
814
 
446
- def prerequisites
447
- Prerequisites.start
815
+ desc('add_jettywrapper_ci_task: FIX', 'FIX')
816
+ def add_jettywrapper_ci_task
817
+ say %Q{
818
+ Instead, we need to add a new Rake task that knows how to wrap the
819
+ test suite -- start jetty before running the tests and stop jetty
820
+ at the end. We can use a feature provided by jettywrapper to do this.\n\n}, STATEMENT
821
+ copy_file 'ci.rake', 'lib/tasks/ci.rake'
822
+ run_git('Added ci task')
823
+ rake 'jetty:stop'
824
+ rake 'ci'
825
+ rake 'jetty:start'
448
826
  end
449
827
 
450
- def building_a_basic_rails_app
451
- return if $quick
828
+ desc('add_coverage_stats: FIX', 'FIX')
829
+ def add_coverage_stats
830
+ say %Q{
831
+ Now that we have tests, we also want to have some coverage statistics.\n}, STATEMENT
452
832
 
453
- inside 'hydra_tutorial_app' do
454
- BuildingABasicRailsApp.start
833
+ gem_group :development, :test do
834
+ gem 'simplecov'
455
835
  end
456
- end
457
-
458
- def application
459
- inside 'hydra_tutorial_app' do
460
- Application.start
836
+ run 'bundle install', :capture => false
837
+
838
+ f = 'lib/tasks/ci.rake'
839
+ remove_file f
840
+ copy_file 'ci_with_coverage.rake', f
841
+
842
+ insert_into_file "spec/spec_helper.rb", :after => "ENV[\"RAILS_ENV\"] ||= 'test'\n"do
843
+ %Q{
844
+ if ENV['COVERAGE'] == "true"
845
+ require 'simplecov'
846
+ SimpleCov.start do
847
+ add_filter "config/"
848
+ add_filter "spec/"
849
+ end
850
+ end
851
+ }
461
852
  end
462
- end
463
853
 
464
- def make_it_nice
465
- return if $quick
466
- inside 'hydra_tutorial_app' do
467
- MakeItNice.start
468
- end
854
+ append_to_file '.gitignore', "\ncoverage\n"
855
+ run_git('Added simplecov')
856
+
857
+ rake 'jetty:stop'
858
+ rake 'ci'
859
+ rake 'jetty:start'
860
+
861
+ say %Q{
862
+ Go take a look at the coverage report, open the file coverage/index.html
863
+ in your browser.\n}, STATEMENT
864
+ continue_prompt
469
865
  end
470
866
 
471
- def tests
472
- inside 'hydra_tutorial_app' do
473
- Tests.start
867
+ desc('add_file_uploads: FIX', 'FIX')
868
+ def add_file_uploads
869
+ say %Q{
870
+ Now that we have a basic Hydra application working with metadata-only, we
871
+ want to enhance that with the ability to upload files. Let's add a new
872
+ datastream to our model.\n\n}, STATEMENT
873
+ inject_into_class 'app/models/record.rb', 'Record' do
874
+ "has_file_datastream :name => 'content', :type => ActiveFedora::Datastream\n"
474
875
  end
876
+ run_git('Add file uploads to model')
475
877
  end
476
878
 
477
- def initial_steps
478
- return if $quick
479
- inside 'hydra_tutorial_app' do
480
- InitialSteps.start
879
+ # TODO: combine with previous task.
880
+ desc('add_file_upload_controller: FIX', 'FIX')
881
+ def add_file_upload_controller
882
+ say %Q{
883
+ And educate our controller for managing file objects.\n\n}, STATEMENT
884
+ inject_into_class "app/controllers/records_controller.rb", "RecordsController" do
885
+ " include Hydra::Controller::UploadBehavior\n"
481
886
  end
887
+ insert_into_file "app/controllers/records_controller.rb", :after => "apply_depositor_metadata(@record)\n" do
888
+ " @record.label = params[:record][:title] # this is a bad hack to work around an AF bug\n" +
889
+ " add_posted_blob_to_asset(@record, params[:filedata]) if params.has_key?(:filedata)\n"
890
+ end
891
+ run_git('Add file uploads to controller')
482
892
  end
483
893
 
484
- def cleanup
485
- yes? "All Done?", Thor::Shell::Color::GREEN
486
- inside 'hydra_tutorial_app' do
487
- Cleanup.start
488
- end
894
+ # TODO: combine with previous task.
895
+ desc('add_file_upload_ui: FIX', 'FIX')
896
+ def add_file_upload_ui
897
+ say %Q{
898
+ And add a file upload field on the form.\n}, STATEMENT
899
+ f = "app/views/records/_form.html.erb"
900
+ remove_file f
901
+ copy_file "_form.add_file_upload.html.erb", f
902
+ run_git('Add file uploads to UI')
903
+ end
904
+
905
+ desc('fix_add_assets_links: FIX', 'FIX')
906
+ def fix_add_assets_links
907
+ say %Q{
908
+ We'll add a little styling to the Hydra app and add a link to add a new
909
+ Record in the header of the layout.\n\n}, STATEMENT
910
+ copy_file "_add_assets_links.html.erb", "app/views/_add_assets_links.html.erb"
911
+ run_git('Add asset links')
912
+ end
913
+
914
+ # # TODO
915
+ # desc('add_collection_model: FIX', 'FIX')
916
+ # def add_collection_model
917
+ # end
918
+
919
+ # # TODO
920
+ # desc('add_collection_controller: FIX', 'FIX')
921
+ # def add_collection_controller
922
+ # end
923
+
924
+ # # TODO
925
+ # desc('add_collection_reference_to_record: FIX', 'FIX')
926
+ # def add_collection_reference_to_record
927
+ # end
928
+
929
+ # # TODO
930
+ # desc('add_datastream_and_terminology: FIX', 'FIX')
931
+ # def add_datastream_and_terminology
932
+ # end
933
+
934
+ desc('start_everything: FIX', 'FIX')
935
+ def start_everything
936
+ say %Q{
937
+ Before the tutorial ends, we'll give you a final chance to look
938
+ at the web application.\n\n}, STATEMENT
939
+ rake 'jetty:stop'
940
+ rake 'jetty:start'
941
+ rails_server
942
+ end
943
+
944
+ desc('stop_jetty: FIX', 'FIX')
945
+ def stop_jetty
946
+ say %Q{
947
+ This is the end of the tutorial. We'll shut down the jetty server.\n}, STATEMENT
948
+ rake 'jetty:stop'
489
949
  end
490
950
 
491
951
  end
492
952
 
493
- HydraTutorialApp.start
953
+
954
+ ####
955
+ #
956
+ ####
957
+
958
+ HydraTutorial.start