doop 0.0.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 (33) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +15 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +203 -0
  6. data/Rakefile +5 -0
  7. data/app/assets/images/dash.gif +0 -0
  8. data/app/assets/images/info-icon.png +0 -0
  9. data/app/assets/images/progress-tick-large.png +0 -0
  10. data/app/helpers/doop_helper.rb +51 -0
  11. data/bin/.gitignore +0 -0
  12. data/doop.gemspec +26 -0
  13. data/lib/doop.rb +313 -0
  14. data/lib/doop/version.rb +3 -0
  15. data/lib/doop_controller.rb +164 -0
  16. data/lib/generators/doopgovuk/USAGE +10 -0
  17. data/lib/generators/doopgovuk/doopgovuk_generator.rb +34 -0
  18. data/lib/generators/doopgovuk/templates/app/assets/stylesheets/demo.css.scss +188 -0
  19. data/lib/generators/doopgovuk/templates/app/controllers/demo_controller.rb +155 -0
  20. data/lib/generators/doopgovuk/templates/app/views/demo/_preamble.html.erb +33 -0
  21. data/lib/generators/doopgovuk/templates/app/views/demo/_summary.html.erb +10 -0
  22. data/lib/generators/doopgovuk/templates/app/views/demo/_your_details.html.erb +55 -0
  23. data/lib/generators/doopgovuk/templates/app/views/demo/index.html.erb +3 -0
  24. data/lib/generators/doopgovuk/templates/app/views/demo/index.js.erb +4 -0
  25. data/lib/generators/doopgovuk/templates/app/views/doop/_error.html.erb +3 -0
  26. data/lib/generators/doopgovuk/templates/app/views/doop/_info_box.html.erb +4 -0
  27. data/lib/generators/doopgovuk/templates/app/views/doop/_navbar.html.erb +23 -0
  28. data/lib/generators/doopgovuk/templates/app/views/doop/_question.html.erb +19 -0
  29. data/lib/generators/doopgovuk/templates/app/views/doop/_question_form.html.erb +15 -0
  30. data/lib/generators/doopgovuk/templates/app/views/layouts/application.html.erb +22 -0
  31. data/spec/doop_spec.rb +448 -0
  32. data/spec/spec_helper.rb +2 -0
  33. metadata +136 -0
@@ -0,0 +1,3 @@
1
+ module Doop
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,164 @@
1
+ require 'yaml'
2
+ require 'rails'
3
+
4
+ module Doop
5
+
6
+ class DoopController
7
+
8
+ delegate :set_yaml, :unanswer_path, :add, :renumber, :on_answer, :answer_with, :enable, :remove, to: :@doop
9
+
10
+ attr_reader :doop
11
+
12
+ def initialize application_controller, &block
13
+ @controller = application_controller
14
+ @block = block
15
+ @debug_on_block = nil
16
+ @current_page_block = method( :default_current_page )
17
+ @all_pages_block = method( :default_all_pages )
18
+ end
19
+
20
+ def index
21
+ render_page in_doop { |doop| doop.ask_next }
22
+ end
23
+
24
+ def answer
25
+ back_val = @controller.params["back_a_page"]
26
+ nav_path = @controller.params["nav_path"]
27
+ change_answer_path = @controller.params["change_answer_path"]
28
+ return back if back_val != nil && !back_val.empty?
29
+ return change_page nav_path if nav_path != nil && !nav_path.empty?
30
+ return change change_answer_path if change_answer_path != nil && !change_answer_path.empty?
31
+
32
+ render_page in_doop { |doop| doop.answer( @controller.params ) }
33
+ end
34
+
35
+ def back
36
+ in_doop do |doop|
37
+ page = get_page_path
38
+ pages = get_all_pages
39
+ i = pages.index(page)
40
+ if i!=0
41
+ path = pages[i-1]
42
+ doop.change( path )
43
+ pages[pages.index(path), pages.length].each do |n|
44
+ doop[n]["_answered"] = false
45
+ end
46
+
47
+ doop.ask_next
48
+ end
49
+ end
50
+ render_page
51
+ end
52
+
53
+ def change path
54
+ res = in_doop do
55
+ |doop| doop.change( path )
56
+ end
57
+ render_page res
58
+ end
59
+
60
+ def change_page path
61
+ in_doop do |doop|
62
+ #path = @controller.params["path"]
63
+ doop.change( path )
64
+
65
+ # unanswer all pages after path
66
+ pages = @all_pages_block.call
67
+ pages[pages.index(path), pages.length].each do |n|
68
+ doop[n]["_answered"] = false
69
+ end
70
+
71
+ doop.ask_next
72
+ end
73
+ render_page
74
+ end
75
+
76
+ def parent_of path
77
+ p = path.split("/")
78
+ p.pop
79
+ p.join("/")
80
+ end
81
+
82
+ def render_page res = {}
83
+ res[:page] = get_page
84
+ res[:page_path] = get_page_path
85
+ res[:page_title] = @doop[res[:page_path]]["_nav_name"]
86
+ res[:all_pages] = get_all_pages
87
+ res[:debug_on] = @debug_on_block != nil ? @debug_on_block.call : false
88
+ @controller.render "index", :locals => { :res => res, :doop => @doop }
89
+ end
90
+
91
+ def load
92
+ @doop = Doop.new()
93
+ @self_before_instance_eval = eval "self", @block.binding
94
+ instance_exec @doop, &@block
95
+ @doop.yaml = @load_yaml_block.call
96
+ @doop.init
97
+ @doop
98
+ end
99
+
100
+ def in_doop
101
+ load
102
+ res = yield(@doop)
103
+ @save_yaml_block.call @doop.dump
104
+ return res if res.kind_of? Hash
105
+ {}
106
+ end
107
+
108
+ def evaluate(block)
109
+ @self_before_instance_eval = eval "self", block.binding
110
+ instance_eval &block
111
+ end
112
+
113
+ def method_missing(method, *args, &block)
114
+ @self_before_instance_eval.send method, *args, &block
115
+ end
116
+
117
+ def current_page &block
118
+ @current_page_block = block
119
+ end
120
+
121
+ def all_pages &block
122
+ @all_pages_block = block
123
+ end
124
+
125
+ def get_page
126
+ path = @doop.currently_asked
127
+ @doop[@current_page_block.call( path )]["_page"]
128
+ end
129
+
130
+ def get_page_path
131
+ path = @doop.currently_asked
132
+ @current_page_block.call( path )
133
+ end
134
+
135
+ def get_all_pages
136
+ @all_pages_block.call
137
+ end
138
+
139
+ def debug_on &block
140
+ @debug_on_block = block
141
+ end
142
+
143
+ def load_yaml &block
144
+ @load_yaml_block = block
145
+ end
146
+
147
+ def save_yaml &block
148
+ @save_yaml_block = block
149
+ end
150
+
151
+ def default_current_page path
152
+ a = path.split("/").reject {|s| s.empty? }[1]
153
+ "/page/#{a}"
154
+ end
155
+
156
+ def default_all_pages
157
+ l = []
158
+ doop.each_question_with_regex_filter "^\/page/\\w+$" do |question,path|
159
+ l << path if doop[path]["_enabled"]
160
+ end
161
+ l
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,10 @@
1
+ Description:
2
+ Creates a demo govuk questionaire. It's fully functional and demonstrates the various integration points with the doop framework.
3
+
4
+ Use this as a starting point for generating any govuk branded website.
5
+
6
+ Example:
7
+ rails generate doopgovuk dvla
8
+ rails s
9
+
10
+ Naviagte to http://localhost:3000
@@ -0,0 +1,34 @@
1
+ class DoopgovukGenerator < Rails::Generators::Base
2
+ source_root File.expand_path('../templates', __FILE__)
3
+ argument :name, :type => :string, :default => "demo"
4
+
5
+
6
+ def generate_layout
7
+ copy_file "app/assets/stylesheets/demo.css.scss", "app/assets/stylesheets/#{name}.css.scss"
8
+ template "app/controllers/demo_controller.rb", "app/controllers/#{name}_controller.rb"
9
+ copy_file "app/views/demo/index.html.erb", "app/views/#{name}/index.html.erb"
10
+ copy_file "app/views/demo/index.js.erb", "app/views/#{name}/index.js.erb"
11
+ copy_file "app/views/demo/_preamble.html.erb", "app/views/#{name}/_preamble.html.erb"
12
+ copy_file "app/views/demo/_summary.html.erb", "app/views/#{name}/_summary.html.erb"
13
+ copy_file "app/views/demo/_your_details.html.erb", "app/views/#{name}/_your_details.html.erb"
14
+ copy_file "app/views/layouts/application.html.erb", "app/views/layouts/application.html.erb"
15
+ copy_file "app/views/doop/_error.html.erb", "app/views/doop/_error.html.erb"
16
+ copy_file "app/views/doop/_info_box.html.erb", "app/views/doop/_info_box.html.erb"
17
+ copy_file "app/views/doop/_navbar.html.erb", "app/views/doop/_navbar.html.erb"
18
+ copy_file "app/views/doop/_question_form.html.erb", "app/views/doop/_question_form.html.erb"
19
+ copy_file "app/views/doop/_question.html.erb", "app/views/doop/_question.html.erb"
20
+
21
+
22
+ route "root '#{name}#index'"
23
+ route "get '#{name}/index'"
24
+ route "post '#{name}/answer'"
25
+
26
+ gem 'govuk_frontend_toolkit'
27
+ gem 'govuk_template'
28
+
29
+ Bundler.with_clean_env do
30
+ run "bundle install"
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,188 @@
1
+ // Place all the styles related to the demo controller here.
2
+ // They will automatically be included in application.css.
3
+ // You can use Sass (SCSS) here: http://sass-lang.com/
4
+
5
+ @import "design-patterns/alpha-beta";
6
+ @import "_conditionals";
7
+ @import "_typography";
8
+ @import "_colours";
9
+ @import "_css3";
10
+ @import "design-patterns/buttons";
11
+
12
+ $question_completed_color: #D2E6DB;
13
+ $question_completed_line_color: #84BA9D;
14
+ $question_completed_font_color: $black;
15
+ $question-fg-color: #014c73;
16
+
17
+
18
+ * {
19
+ -webkit-box-sizing: border-box;
20
+ -moz-box-sizing: border-box;
21
+ box-sizing: border-box;
22
+ }
23
+
24
+ .phase-banner {
25
+ @include phase-banner(alpha);
26
+ }
27
+
28
+ .outer-block {
29
+ @include outer-block;
30
+ }
31
+
32
+ .inner-block {
33
+ @include inner-block;
34
+ margin: 0 0 15px 0;
35
+ }
36
+
37
+ .info_box {
38
+ display: block;
39
+ margin: 15px 0 15px 0;
40
+ max-width: 100%;
41
+ min-height: 60px;
42
+ //outline: solid #a1bfd8 1px;
43
+ border: solid #d1e4f2 5px;
44
+ padding: 0 0 0 0;
45
+ background: #e1effa;
46
+ border-radius: 0.15em;
47
+ p {
48
+ margin: 0.75em 0.75em 0.75em 0.75em;
49
+ }
50
+
51
+ .info_img {
52
+ float: right;
53
+ margin: 10px 10px 10px 10px;
54
+ }
55
+ }
56
+
57
+ .question-open {
58
+ margin: 16px 0 16px 0;
59
+
60
+ }
61
+
62
+ .indent {
63
+ margin: 0 0 0 10px;
64
+ }
65
+
66
+ .question-closed {
67
+ background: $question_completed_color;
68
+ border-bottom: solid $question_completed_line_color 1px;
69
+ color: $question_completed_font_color;
70
+ display: table;
71
+ padding: 0.5em 0.5em 0.5em 0.5em;
72
+ margin: 0 0 0 0;
73
+ width: 100%;
74
+
75
+ .title {
76
+ padding: 0 0 0 0;
77
+ display: table-cell;
78
+ width: 80%;
79
+ vertical-align: middle;
80
+ }
81
+
82
+ .answer {
83
+ display: table-cell;
84
+ max-width: 20%;
85
+ text-align: right;
86
+ vertical-align: middle;
87
+ .button {
88
+ @include button($question-fg-color);
89
+ margin: 0 0 0 0;
90
+ }
91
+ }
92
+
93
+ }
94
+
95
+ .question_form {
96
+ @include core-16();
97
+ width: 100%;
98
+ h1 {
99
+ @include bold-36();
100
+ border-width: 0 0 2px 0;
101
+ border-style: solid;
102
+ border-color: #d43783;
103
+ margin: 0 0 0 0;
104
+ padding: 5px 0 5px 0;
105
+ }
106
+
107
+ h2 {
108
+ @include bold-27();
109
+ padding: 0 0 10px 0;
110
+ }
111
+
112
+ input {
113
+ @include core-16();
114
+ width: 200px;
115
+ }
116
+
117
+ }
118
+
119
+
120
+ .textfield {
121
+
122
+ margin: 0 0 10px 0;
123
+
124
+ label {
125
+ display: block;
126
+ @include bold-16();
127
+ margin: 0 0 1px 0;
128
+ }
129
+
130
+ }
131
+
132
+ button {
133
+ @include button;
134
+ margin: 16px 0 0 0;
135
+
136
+ }
137
+
138
+ .button-secondary{
139
+ @include button($grey-3);
140
+ }
141
+
142
+ .button-warning {
143
+ @include button($red);
144
+ }
145
+
146
+ .error {
147
+ margin: 0 0 10px 0;
148
+ span {
149
+ color: red;
150
+ border: 1px solid #B01117;
151
+ background-color: #FFF3CF;
152
+ padding: 5px 5px 5px 5px;
153
+ border-radius: 5px;
154
+
155
+ }
156
+ }
157
+
158
+ .navbar {
159
+
160
+ border-width: 0 0 1px 0;
161
+ border-style: dotted;
162
+ border-color: #bfc1c3;
163
+
164
+ ol {
165
+ list-style-type: none;
166
+ margin: 0;
167
+ padding: 10px;
168
+ text-align: center;
169
+ }
170
+ li.todo {
171
+ display: inline;
172
+ margin: 0 30px 0 0;
173
+ @include core-16();
174
+ }
175
+
176
+ li.doing {
177
+ display: inline;
178
+ margin: 0 30px 0 0;
179
+ @include bold-16();
180
+ }
181
+
182
+ li.done {
183
+ display: inline;
184
+ margin: 0 30px 0 0;
185
+ @include core-16();
186
+ }
187
+ }
188
+
@@ -0,0 +1,155 @@
1
+
2
+ require 'doop'
3
+ require 'yaml'
4
+
5
+ class <%=name.capitalize%>Controller < ApplicationController
6
+
7
+ delegate :index, :answer, to: :@doop_controller
8
+ before_filter :setup_doop
9
+
10
+ def setup_doop
11
+ @doop_controller = Doop::DoopController.new self do |doop|
12
+
13
+ load_yaml do
14
+ data = params["doop_data"]
15
+ if data != nil
16
+ crypt = ActiveSupport::MessageEncryptor.new(Rails.application.secrets.secret_key_base)
17
+ next crypt.decrypt_and_verify data
18
+ end
19
+
20
+ <<-EOS
21
+ page: {
22
+ preamble: {
23
+ _page: "preamble",
24
+ _nav_name: "Apply Online",
25
+
26
+ debug_on: {
27
+ _question: "Turn debug on ?",
28
+ _answer: "No"
29
+ },
30
+ enrolled_before: {
31
+ _question: "Have you enrolled for this service before ?"
32
+ },
33
+ year_last_applied: {
34
+ _question: "What year did you last apply?"
35
+ },
36
+ reason_for_applying: {
37
+ _question: "Why are you applying?"
38
+ }
39
+ },
40
+ your_details: {
41
+ _page: "your_details",
42
+ _nav_name: "Your Details",
43
+
44
+ your_name: {
45
+ _question: "What is your name?",
46
+ _answer: {},
47
+ },
48
+ address_history: {
49
+ _question: "What is your address ?",
50
+ address__1: { _answer: {} }
51
+ }
52
+
53
+ },
54
+ summary: {
55
+ _page: "summary",
56
+ _nav_name: "Summary",
57
+
58
+ terms_and_conditions: {
59
+ _question: "Terms and conditions"
60
+ }
61
+ }
62
+
63
+ }
64
+ EOS
65
+
66
+ end
67
+
68
+ save_yaml do |yaml|
69
+ crypt = ActiveSupport::MessageEncryptor.new(Rails.application.secrets.secret_key_base)
70
+ data = crypt.encrypt_and_sign(yaml)
71
+ request["doop_data"] = data
72
+ end
73
+
74
+ debug_on do
75
+ doop["/page/preamble/debug_on/_answer"] == "Yes"
76
+ end
77
+
78
+ # On answer call backs
79
+
80
+ on_answer "/page/preamble/debug_on" do |question,path, params, answer|
81
+ answer_with( question, { "_summary" => answer } )
82
+ end
83
+
84
+ on_answer "/page/preamble/enrolled_before" do |question,path, params, answer|
85
+ answer_with( question, { "_summary" => answer } )
86
+ enable( "/page/preamble/year_last_applied", answer == "Yes" )
87
+ end
88
+
89
+ on_answer "/page/preamble/year_last_applied" do |question,path,params,answer|
90
+ answer_with( question, { "_summary" => answer } )
91
+ end
92
+
93
+ on_answer "/page/preamble/reason_for_applying" do |question,path,params,answer|
94
+ if answer.empty?
95
+ next { :reason_for_applying_error => "This can not be blank" }
96
+ end
97
+
98
+ answer_with( question, { "_summary" => "Provided" } )
99
+ end
100
+
101
+ on_answer( "/page/preamble" ) do |question, path, params, answer|
102
+ answer_with( question, { "_summary" => "Provided" } )
103
+ end
104
+
105
+ on_answer( "/page/your_details/your_name" ) do |question, path, params, answer|
106
+ firstname = answer["firstname"].capitalize
107
+ surname = answer["surname"].capitalize
108
+ answer_with( question, { "_summary" => "#{firstname} #{surname}" } )
109
+ end
110
+
111
+ on_answer( "/page/your_details/address_history/address__(\\d+)" ) do |question, path, params, answer|
112
+
113
+ if params.include?("remove_address")
114
+ remove path
115
+ next
116
+ end
117
+
118
+ address1 = answer["address1"]
119
+ address2 = answer["address2"]
120
+ address3 = answer["address3"]
121
+ postcode = answer["postcode"]
122
+ summary = [address1, address2, address3, postcode].select{ |n| !n.empty? }.join( ", ")
123
+ answer_with( question, { "_summary" => summary } )
124
+
125
+ end
126
+
127
+ on_answer( "/page/your_details/address_history" ) do |question, path, params, answer|
128
+ if params.include?("add_address")
129
+ address = YAML.load("{ _answer: {}}")
130
+ add( "/page/your_details/address_history/address__99", address )
131
+ renumber( "/page/your_details/address_history" )
132
+ next
133
+ end
134
+
135
+ answer_with( question, { "_summary" => "Provided" } )
136
+ end
137
+
138
+ on_answer( "/page/your_details" ) do |question, path, params, answer|
139
+ answer_with( question, { "_summary" => "Provided" } )
140
+ end
141
+
142
+ on_answer( "/page/your_details" ) do |question, path, params, answer|
143
+ answer_with( question, { "_summary" => "Provided" } )
144
+ end
145
+
146
+ on_answer( "/page/summary/terms_and_conditions" ) do |question, path, params, answer|
147
+ answer_with( question, { "_summary" => "Accepted" } )
148
+ end
149
+
150
+ end
151
+ end
152
+
153
+
154
+ end
155
+