cloudfactory 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/.gitignore +11 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +10 -0
  4. data/README.md +44 -0
  5. data/Rakefile +40 -0
  6. data/bin/cf +8 -0
  7. data/cf.gemspec +76 -0
  8. data/example/google_translate_app/Gemfile +12 -0
  9. data/example/google_translate_app/config.ru +7 -0
  10. data/example/google_translate_app/google_translate_input.csv +4 -0
  11. data/example/google_translate_app/google_translator_app.rb +53 -0
  12. data/example/google_translate_app/views/index.haml +2 -0
  13. data/example/google_translate_app/views/layout.haml +7 -0
  14. data/example/google_translate_app/views/run.haml +4 -0
  15. data/example/google_translate_app/views/style.sass +2 -0
  16. data/example/human_worker_app/Gemfile +12 -0
  17. data/example/human_worker_app/config.ru +7 -0
  18. data/example/human_worker_app/human_worker_app.rb +55 -0
  19. data/example/human_worker_app/human_worker_input.csv +5 -0
  20. data/example/human_worker_app/public/app.js +12 -0
  21. data/example/human_worker_app/temp.csv +3 -0
  22. data/example/human_worker_app/views/index.haml +15 -0
  23. data/example/human_worker_app/views/layout.haml +10 -0
  24. data/example/human_worker_app/views/result.haml +18 -0
  25. data/example/human_worker_app/views/run.haml +12 -0
  26. data/example/human_worker_app/views/style.sass +25 -0
  27. data/example/sample_yaml_files/concept_tagging_robot.yaml +18 -0
  28. data/example/sample_yaml_files/content_scraping_robot.yaml +19 -0
  29. data/example/sample_yaml_files/entity_extraction_robot.yaml +18 -0
  30. data/example/sample_yaml_files/google_translate_robot.yaml +20 -0
  31. data/example/sample_yaml_files/image_processing_robot.yaml +20 -0
  32. data/example/sample_yaml_files/keyword_matching_and_text_extraction_robot.yaml +26 -0
  33. data/example/sample_yaml_files/mailer_robot.yaml +21 -0
  34. data/example/sample_yaml_files/media_converter_robot.yaml +21 -0
  35. data/example/sample_yaml_files/media_splitting_robot.yaml +20 -0
  36. data/example/sample_yaml_files/multiple_skill_badge.yaml +75 -0
  37. data/example/sample_yaml_files/sentiment_robot.yaml +19 -0
  38. data/example/sample_yaml_files/skill_badge.yaml +56 -0
  39. data/example/sample_yaml_files/stat_badge.yaml +40 -0
  40. data/example/sample_yaml_files/term_extraction_robot.yaml +20 -0
  41. data/example/sample_yaml_files/tournament_station_and_form_fields.yaml +40 -0
  42. data/features/form_generation.feature +46 -0
  43. data/features/form_preview.feature +98 -0
  44. data/features/line_creation.feature +99 -0
  45. data/features/line_deletion.feature +50 -0
  46. data/features/line_generation.feature +57 -0
  47. data/features/run.feature +141 -0
  48. data/features/support/cli_steps.rb +16 -0
  49. data/features/support/env.rb +23 -0
  50. data/features/target_url.feature +82 -0
  51. data/fixtures/api_credentials_example.yml +4 -0
  52. data/fixtures/input_data/media_converter_robot.csv +2 -0
  53. data/fixtures/input_data/test.csv +2 -0
  54. data/lib/cf.rb +94 -0
  55. data/lib/cf/account.rb +32 -0
  56. data/lib/cf/cli.rb +52 -0
  57. data/lib/cf/cli/config.rb +87 -0
  58. data/lib/cf/cli/form.rb +82 -0
  59. data/lib/cf/cli/line.rb +237 -0
  60. data/lib/cf/cli/production.rb +62 -0
  61. data/lib/cf/cli/templates/css_file.css.erb +22 -0
  62. data/lib/cf/cli/templates/form_preview.html.erb +17 -0
  63. data/lib/cf/cli/templates/html_file.html.erb +21 -0
  64. data/lib/cf/cli/templates/js_file.js.erb +18 -0
  65. data/lib/cf/cli/templates/line.tt +55 -0
  66. data/lib/cf/cli/templates/sample-line/form.css +27 -0
  67. data/lib/cf/cli/templates/sample-line/form.html +26 -0
  68. data/lib/cf/cli/templates/sample-line/form.js +7 -0
  69. data/lib/cf/cli/templates/sample-line/line.yml.erb +67 -0
  70. data/lib/cf/cli/templates/sample-line/sample-line.csv +3 -0
  71. data/lib/cf/client.rb +56 -0
  72. data/lib/cf/custom_task_form.rb +136 -0
  73. data/lib/cf/department.rb +24 -0
  74. data/lib/cf/final_output.rb +20 -0
  75. data/lib/cf/form_field.rb +62 -0
  76. data/lib/cf/human_worker.rb +67 -0
  77. data/lib/cf/input_format.rb +134 -0
  78. data/lib/cf/line.rb +231 -0
  79. data/lib/cf/robot_worker.rb +31 -0
  80. data/lib/cf/run.rb +158 -0
  81. data/lib/cf/station.rb +340 -0
  82. data/lib/cf/task_form.rb +147 -0
  83. data/lib/cf/version.rb +3 -0
  84. data/lib/generators/cf/form/form_generator.rb +55 -0
  85. data/lib/generators/cf/form/templates/cf_form.html.erb +11 -0
  86. data/lib/generators/cf/install/install_generator.rb +22 -0
  87. data/lib/generators/cf/install/templates/README +13 -0
  88. data/lib/generators/cf/install/templates/cloud_factory.rb +7 -0
  89. data/spec/account_spec.rb +11 -0
  90. data/spec/badge_spec.rb +88 -0
  91. data/spec/concept_tagging_robot_spec.rb +54 -0
  92. data/spec/config_spec.rb +20 -0
  93. data/spec/content_scraping_robot_spec.rb +58 -0
  94. data/spec/custom_task_form_spec.rb +190 -0
  95. data/spec/department_spec.rb +14 -0
  96. data/spec/entity_extraction_robot_spec.rb +56 -0
  97. data/spec/form_field_spec.rb +126 -0
  98. data/spec/generators/form_generator_spec.rb +60 -0
  99. data/spec/generators/install_generator_spec.rb +35 -0
  100. data/spec/google_translate_robot_spec.rb +64 -0
  101. data/spec/human_worker_spec.rb +118 -0
  102. data/spec/image_processing_robot_spec.rb +56 -0
  103. data/spec/input_format_spec.rb +113 -0
  104. data/spec/keyword_matching_and_text_extraction_robot_spec.rb +73 -0
  105. data/spec/line_spec.rb +338 -0
  106. data/spec/mailer_robot_spec.rb +62 -0
  107. data/spec/media_converter_robot_spec.rb +72 -0
  108. data/spec/media_splitting_robot_spec.rb +62 -0
  109. data/spec/run_spec.rb +298 -0
  110. data/spec/sentiment_robot_spec.rb +56 -0
  111. data/spec/spec_helper.rb +39 -0
  112. data/spec/station_spec.rb +256 -0
  113. data/spec/task_form_spec.rb +96 -0
  114. data/spec/term_extraction_robot_spec.rb +58 -0
  115. data/spec/text_appending_robot_spec.rb +86 -0
  116. metadata +472 -0
@@ -0,0 +1,16 @@
1
+ Then /^I should see "([^"]*)"$/ do |expected|
2
+ assert_partial_output(expected, all_output)
3
+ end
4
+
5
+ When /^I type "([^"]*)" and press Enter$/ do |text|
6
+ type(text)
7
+ end
8
+
9
+ Then /^I debug$/ do
10
+ breakpoint
11
+ 0
12
+ end
13
+
14
+ Then /^the file "([^"]*)" should contain:$/ do |file, partial_content|
15
+ check_file_content(file, partial_content, true)
16
+ end
@@ -0,0 +1,23 @@
1
+ require 'ruby-debug'
2
+ require 'aruba/cucumber'
3
+ require 'cf'
4
+ ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
5
+
6
+ Before('@slow_process') do
7
+ @aruba_io_wait_seconds = 4
8
+ @aruba_timeout_seconds = 4
9
+ end
10
+
11
+ Before('@too_slow_process') do
12
+ @aruba_io_wait_seconds = 4
13
+ @aruba_timeout_seconds = 50
14
+ end
15
+
16
+ if ENV['TEST_CLI']
17
+ API_CONFIG = YAML.load_file(File.expand_path("../../../fixtures/api_credentials.yml", __FILE__))
18
+ CF.configure do |config|
19
+ config.api_version = API_CONFIG['api_version']
20
+ config.api_url = API_CONFIG['api_url']
21
+ config.api_key = API_CONFIG['api_key']
22
+ end
23
+ end
@@ -0,0 +1,82 @@
1
+ Feature: Target URL
2
+ In order to talk with cloud factory
3
+ As a CLI user
4
+ I want to setup login credentials
5
+
6
+ Scenario: Setting up staging target uri
7
+ When I run `cf target staging`
8
+ Then the file ".cf_credentials" should contain exactly:
9
+ """
10
+ ---
11
+ :target_url: http://sandbox.staging.cloudfactory.com/api/
12
+ :api_version: v1
13
+
14
+ """
15
+ Then the output should match:
16
+ """
17
+
18
+ Your cloudfactory target url is saved as http://sandbox.staging.cloudfactory.com/api/
19
+ All the best to run your factory on top of CloudFactory.com
20
+
21
+ """
22
+
23
+ Scenario: Setting up development target uri
24
+ When I run `cf target development`
25
+ Then the file ".cf_credentials" should contain exactly:
26
+ """
27
+ ---
28
+ :target_url: http://lvh.me:3000/api/
29
+ :api_version: v1
30
+
31
+ """
32
+ Then the output should match:
33
+ """
34
+
35
+ Your cloudfactory target url is saved as http://lvh.me:3000/api/
36
+ All the best to run your factory on top of CloudFactory.com
37
+
38
+ """
39
+
40
+ Scenario: Setting up production target uri
41
+ When I run `cf target production`
42
+ Then the file ".cf_credentials" should contain exactly:
43
+ """
44
+ ---
45
+ :target_url: http://sandbox.cloudfactory.com/api/
46
+ :api_version: v1
47
+
48
+ """
49
+ Then the output should match:
50
+ """
51
+
52
+ Your cloudfactory target url is saved as http://sandbox.cloudfactory.com/api/
53
+ All the best to run your factory on top of CloudFactory.com
54
+
55
+ """
56
+
57
+ Scenario: Show the current target if no param is passed
58
+ Given a file named ".cf_credentials" with:
59
+ """
60
+ ---
61
+ :target_url: http://sandbox.staging.cloudfactory.com/api/
62
+ :api_version: v1
63
+
64
+ """
65
+ When I run `cf target`
66
+ Then the output should match:
67
+ """
68
+
69
+ http://sandbox.staging.cloudfactory.com/api/
70
+
71
+ """
72
+
73
+ Scenario: Show the message to set the target uri if no param is passed and the .cf_credentials file does not exist
74
+ When I run `cf target`
75
+ Then the output should match:
76
+ """
77
+
78
+ You have not set the target url yet.
79
+ Set the target uri with: cf target --url=http://sandbox.staging.cloudfactory.com
80
+
81
+ """
82
+
@@ -0,0 +1,4 @@
1
+ account_name: "manish"
2
+ api_key: "f488a62d0307e79ec4f1e6131fa220be47e83d44"
3
+ api_version: "v1"
4
+ api_url: "http://manish.lvh.me:3000/api/"
@@ -0,0 +1,2 @@
1
+ url_1
2
+ http://media-robot.s3.amazonaws.com/media_robot/p.mp3
@@ -0,0 +1,2 @@
1
+ Company,Website,meta_data_company
2
+ Apple,apple.com,Apple
data/lib/cf.rb ADDED
@@ -0,0 +1,94 @@
1
+ begin
2
+ require 'psych'
3
+ rescue LoadError
4
+ # do nothing
5
+ end
6
+ require 'yaml'
7
+ require 'rails'
8
+ require 'hashie'
9
+ require 'active_support/concern'
10
+ #require 'active_support/rescuable'
11
+ require 'active_support/core_ext/string/inflections'
12
+ require 'active_support/core_ext/object/blank'
13
+ require 'active_support/core_ext/object/try'
14
+ require "rest_client"
15
+ require 'json'
16
+ require 'terminal-table/import'
17
+
18
+ directory = File.expand_path(File.dirname(__FILE__))
19
+
20
+ Hash.send :include, Hashie::HashExtensions
21
+
22
+
23
+ module CF
24
+
25
+ class << self
26
+ attr_accessor :api_key, :account_name, :api_version, :api_url
27
+ def configure
28
+ yield self
29
+ end
30
+ end
31
+
32
+ # FIX: raise the exception along with the response error message
33
+ # Ref: http://www.simonecarletti.com/blog/2009/12/inside-ruby-on-rails-rescuable-and-rescue_from/
34
+ # class CFError < StandardError
35
+ #
36
+ # include ActiveSupport::Rescuable
37
+ #
38
+ # attr_reader :data
39
+ # rescue_from NotFound, :with => :render_error
40
+ #
41
+ # def initialize(data)
42
+ # @data = data
43
+ # # debugger
44
+ # super
45
+ # end
46
+ #
47
+ # def to_s
48
+ # "Error: #{@data}"
49
+ # end
50
+ #
51
+ # def render_error(exception)
52
+ # @error = exception
53
+ # "Error: #{exception.class}: #{exception.message}"
54
+ # debugger
55
+ # puts ""
56
+ # end
57
+ #
58
+ # end
59
+ #
60
+ #
61
+ # class ClientError < StandardError; end
62
+ # class ServerError < CFError; end
63
+ # class General < CFError; end
64
+ #
65
+ class CFError < StandardError; end
66
+ class ImproveStationNotAllowed < CFError; end
67
+ #
68
+ # class Unauthorized < ClientError; end
69
+ # class NotFound < ClientError
70
+ # # attr_accessor :data
71
+ # # def initialize(data)
72
+ # #
73
+ # # @data = data
74
+ # # debugger
75
+ # # puts ""
76
+ # # end
77
+ # end
78
+ #
79
+ # class Unavailable < StandardError; end
80
+ end
81
+
82
+ require "#{directory}/cf/client"
83
+ require "#{directory}/cf/account"
84
+ require "#{directory}/cf/line"
85
+ require "#{directory}/cf/input_format"
86
+ require "#{directory}/cf/station"
87
+ require "#{directory}/cf/human_worker"
88
+ require "#{directory}/cf/task_form"
89
+ require "#{directory}/cf/form_field"
90
+ require "#{directory}/cf/custom_task_form"
91
+ require "#{directory}/cf/run"
92
+ require "#{directory}/cf/department"
93
+ require "#{directory}/cf/final_output"
94
+ require "#{directory}/cf/robot_worker"
data/lib/cf/account.rb ADDED
@@ -0,0 +1,32 @@
1
+ module CF
2
+ class Account
3
+ include Client
4
+
5
+ class << self
6
+ attr_accessor :errors
7
+
8
+ def info
9
+ resp = get('/account.json')
10
+
11
+ if resp.code != 200
12
+ self.errors = resp.error.message
13
+ end
14
+ return resp
15
+ end
16
+
17
+ def valid?
18
+ info
19
+ errors.nil?
20
+ end
21
+
22
+ def login(email, passwd)
23
+ resp = post('/api_login.json', {:email => email, :password => passwd})
24
+
25
+ if resp.code != 200
26
+ self.errors = resp.error.message
27
+ end
28
+ return resp
29
+ end
30
+ end
31
+ end
32
+ end
data/lib/cf/cli.rb ADDED
@@ -0,0 +1,52 @@
1
+ begin
2
+ require 'psych'
3
+ rescue LoadError
4
+ # do nothing
5
+ end
6
+ require 'yaml'
7
+ require 'fileutils'
8
+ require 'thor'
9
+
10
+ require File.expand_path('../../cf', __FILE__) #=> requiring the gem
11
+ require 'active_support/core_ext/string/inflections'
12
+ require 'active_support/core_ext/object/blank'
13
+
14
+ cli_directory = File.expand_path("../cf/cli", File.dirname(__FILE__))
15
+ require "#{cli_directory}/config"
16
+ require "#{cli_directory}/line"
17
+ require "#{cli_directory}/form"
18
+ require "#{cli_directory}/production"
19
+
20
+ module Cf
21
+ class CLI < Thor
22
+ include Thor::Actions
23
+ include Cf::Config
24
+
25
+ desc "target", "Setup the cloudfactory credentials. e.g. cf target staging #=> http://sandbox.staging.cloudfactory.com (options: staging/development/production)"
26
+ def target(target_url=nil)
27
+ if target_url.present?
28
+ target_set_url = save_config(target_url)
29
+ say("\nYour cloudfactory target url is saved as #{target_set_url}", :green)
30
+ say("All the best to run your factory on top of CloudFactory.com\n", :green)
31
+ else
32
+ if load_config
33
+ say("\n#{load_config[:target_url]}\n", :green)
34
+ else
35
+ say("\nYou have not set the target url yet.", :yellow)
36
+ say("Set the target uri with: cf target --url=http://sandbox.staging.cloudfactory.com\n", :yellow)
37
+ end
38
+ end
39
+ end
40
+
41
+ desc "line", "Commands to manage the Lines. For more info, cf line help"
42
+ subcommand "line", Cf::Line
43
+
44
+ desc "form", "Commands to generate custom task forms. For more info, cf form help"
45
+ subcommand "form", Cf::Form
46
+
47
+ desc "production", "Commands to create production runs. For more info, cf production help"
48
+ # cannot use Run for the class name coz its a reserved word for Thor
49
+ # later it can be replaced with hacked millisami-thor version of the thor library with run-time dependency via Bundler
50
+ subcommand "production", Cf::Production
51
+ end
52
+ end
@@ -0,0 +1,87 @@
1
+ module Cf
2
+ module Config
3
+ def config_file
4
+ File.join(find_home, '.cf_credentials')
5
+ end
6
+
7
+ def load_config
8
+ YAML::load(File.read(config_file)) if File.exist?(config_file)
9
+ end
10
+
11
+ def save_config(target_url)
12
+ if target_url == "staging"
13
+ target_set_url = "http://sandbox.staging.cloudfactory.com/api/"
14
+ elsif target_url == "development"
15
+ target_set_url = "http://lvh.me:3000/api/"
16
+ elsif target_url == "production"
17
+ target_set_url = "http://sandbox.cloudfactory.com/api/"
18
+ end
19
+ File.open(config_file, 'w') {|f| f.write({ :target_url => "#{target_set_url}", :api_version => "v1" }.to_yaml) }
20
+ return target_set_url
21
+ end
22
+
23
+ def set_target_uri(live)
24
+ if load_config
25
+ CF.api_url = load_config[:target_url]
26
+ CF.api_version = load_config[:api_version]
27
+ else
28
+ CF.api_url = "http://sandbox.cloudfactory.com/api"
29
+ CF.api_version = "v1"
30
+ end
31
+
32
+ if live
33
+ if CF.api_url == "http://sandbox.staging.cloudfactory.com/api"
34
+ CF.api_url = "http://staging.cloudfactory.com/api"
35
+ end
36
+
37
+ if CF.api_url == "http://sandbox.cloudfactory.com/api"
38
+ CF.api_url = "http://cloudfactory.com/api"
39
+ end
40
+ end
41
+ end
42
+
43
+ def get_api_key(line_yaml_file)
44
+ line_yml = YAML::load(File.read(line_yaml_file))
45
+ line_yml['api_key'].presence
46
+ end
47
+
48
+ def set_api_key(yaml_source)
49
+ # debugger
50
+ api_key = get_api_key(yaml_source)
51
+ if api_key.blank?
52
+ return false
53
+ else
54
+ CF.api_key = api_key if CF.api_key.blank?
55
+ return true
56
+ end
57
+ end
58
+
59
+ # Ripped from rubygems
60
+ unless ENV['TEST_CLI']
61
+ def find_home
62
+ unless RUBY_VERSION > '1.9' then
63
+ ['HOME', 'USERPROFILE'].each do |homekey|
64
+ return File.expand_path(ENV[homekey]) if ENV[homekey]
65
+ end
66
+
67
+ if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] then
68
+ return File.expand_path("#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}")
69
+ end
70
+ end
71
+
72
+ File.expand_path "~"
73
+ rescue
74
+ if File::ALT_SEPARATOR then
75
+ drive = ENV['HOMEDRIVE'] || ENV['SystemDrive']
76
+ File.join(drive.to_s, '/')
77
+ else
78
+ "/"
79
+ end
80
+ end
81
+ else
82
+ def find_home
83
+ File.expand_path(File.dirname(__FILE__) + '/../../../tmp/aruba')
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,82 @@
1
+ require 'thor/group'
2
+
3
+ module Cf
4
+ class Newform < Thor::Group
5
+ include Thor::Actions
6
+ include Cf::Config
7
+ source_root File.expand_path('../templates', __FILE__)
8
+ argument :station, :type => :numeric
9
+ argument :labels, :type => :string
10
+ argument :fields, :type => :hash
11
+
12
+ def generate_form_template
13
+ line_destination = Dir.pwd
14
+ template("html_file.html.erb", "#{line_destination}/station_#{station}/form.html")
15
+ template("css_file.css.erb", "#{line_destination}/station_#{station}/form.css")
16
+ template("js_file.js.erb", "#{line_destination}/station_#{station}/form.js")
17
+ end
18
+ end
19
+
20
+ class FormPreview < Thor::Group
21
+ include Thor::Actions
22
+ include Cf::Config
23
+ source_root File.expand_path('../templates', __FILE__)
24
+ argument :station, :type => :numeric
25
+ argument :form_content, :type => :string
26
+
27
+ def generate_form_preview
28
+ line_destination = Dir.pwd
29
+ template("form_preview.html.erb", "#{line_destination}/station_#{station}/form_preview.html")
30
+ end
31
+
32
+ def launch_preview
33
+ line_destination = Dir.pwd
34
+ system "open #{line_destination}/station_#{station}/form_preview.html"
35
+ end
36
+ end
37
+ end
38
+
39
+ module Cf
40
+ class Form < Thor
41
+ include Cf::Config
42
+
43
+ desc "form generate", "generates a custom task form at <line-title>/<form-title>.html and its associated css and js files"
44
+ method_option :station, :type => :numeric, :required => true, :aliases => "-st", :desc => "the station index this form should be associated with"
45
+ method_option :labels, :type => :string, :required => true, :aliases => "-lb", :desc => "the labels that will be shown to the worker on MTurk window"
46
+ method_option :fields, :type => :hash, :required => true, :aliases => "-fd", :desc => "the actual form fields that the worker will fill in"
47
+ method_option :force, :type => :boolean, :default => false, :aliases => "-f", :desc => "force to overwrite the files if the form already exists, default is false"
48
+
49
+ def generate
50
+ line_destination = Dir.pwd
51
+ unless File.exist?("#{line_destination}/line.yml")
52
+ say("The current directory is not a valid line directory.", :red) and return
53
+ end
54
+
55
+ FileUtils.rm_rf("#{line_destination}/station_#{options[:station]}", :verbose => true) if options.force? && Dir.exist?("#{line_destination}/station_#{options[:station]}")
56
+ if Dir.exist?("#{line_destination}/station_#{options[:station]}")
57
+ say "Skipping the form generation because the station_#{options[:station]} already exists with its custom form.\nUse the -f flag to force it to overwrite or check and delete the station_#{options[:station]} folder manually.", :red
58
+ else
59
+ say "Generating form for station #{options[:station]}", :green
60
+ Cf::Newform.start([options[:station], options[:labels], options[:fields]])
61
+ say "A new custom task form created in station_#{options[:station]}."
62
+ end
63
+ end
64
+
65
+ desc "form preview", "generates a html file to preview the custom task form"
66
+ method_option :station, :type => :numeric, :required => true, :aliases => "-s", :desc => "station index of the form to preview"
67
+ def preview
68
+ line_destination = Dir.pwd
69
+ unless File.exist?("#{line_destination}/line.yml")
70
+ say("The current directory is not a valid line directory.", :red) and return
71
+ end
72
+ if Dir.exist?("#{line_destination}/station_#{options[:station]}") and !Dir["#{line_destination}/station_#{options[:station]}/*"].empty?
73
+ say "Generating preview form for station #{options[:station]}", :green
74
+ form_content = File.read("station_#{options[:station]}/form.html")
75
+ Cf::FormPreview.start([options[:station], form_content])
76
+ else
77
+ say "No form exists for station #{options[:station]}", :red
78
+ say "Generate the form for station 2 and then preview it.", :red
79
+ end
80
+ end
81
+ end
82
+ end