volt 0.9.6 → 0.9.7.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/CHANGELOG.md +26 -0
  4. data/Gemfile +6 -1
  5. data/README.md +2 -0
  6. data/Rakefile +1 -0
  7. data/app/volt/models/active_volt_instance.rb +8 -6
  8. data/app/volt/models/user.rb +11 -2
  9. data/app/volt/models/volt_app_property.rb +8 -0
  10. data/app/volt/tasks/query_tasks.rb +23 -31
  11. data/app/volt/tasks/store_tasks.rb +2 -2
  12. data/app/volt/tasks/volt_admin_tasks.rb +24 -0
  13. data/docs/UPGRADE_GUIDE.md +6 -0
  14. data/lib/volt.rb +19 -12
  15. data/lib/volt/boot.rb +1 -0
  16. data/lib/volt/cli.rb +19 -8
  17. data/lib/volt/cli/console.rb +0 -1
  18. data/lib/volt/cli/generators.rb +14 -3
  19. data/lib/volt/cli/migrate.rb +26 -0
  20. data/lib/volt/config.rb +17 -4
  21. data/lib/volt/controllers/http_controller.rb +12 -0
  22. data/lib/volt/data_stores/base_adaptor_client.rb +2 -2
  23. data/lib/volt/data_stores/base_adaptor_server.rb +2 -0
  24. data/lib/volt/data_stores/data_store.rb +20 -14
  25. data/lib/volt/extra_core/class.rb +28 -14
  26. data/lib/volt/extra_core/hash.rb +5 -0
  27. data/lib/volt/extra_core/string.rb +3 -1
  28. data/lib/volt/helpers/time.rb +9 -43
  29. data/lib/volt/helpers/time/calculations.rb +204 -0
  30. data/lib/volt/helpers/time/distance.rb +63 -0
  31. data/lib/volt/helpers/time/duration.rb +71 -0
  32. data/lib/volt/helpers/time/local_calculations.rb +49 -0
  33. data/lib/volt/helpers/time/local_volt_time.rb +23 -0
  34. data/lib/volt/helpers/time/numeric.rb +59 -0
  35. data/lib/volt/helpers/time/volt_time.rb +170 -0
  36. data/lib/volt/models.rb +5 -0
  37. data/lib/volt/models/array_model.rb +33 -6
  38. data/lib/volt/models/associations.rb +146 -23
  39. data/lib/volt/models/buffer.rb +38 -41
  40. data/lib/volt/models/cursor.rb +15 -0
  41. data/lib/volt/models/errors.rb +11 -0
  42. data/lib/volt/models/field_helpers.rb +108 -68
  43. data/lib/volt/models/helpers/array_model.rb +4 -0
  44. data/lib/volt/models/helpers/base.rb +8 -1
  45. data/lib/volt/models/helpers/change_helpers.rb +31 -12
  46. data/lib/volt/models/helpers/defaults.rb +15 -0
  47. data/lib/volt/models/location.rb +20 -6
  48. data/lib/volt/models/migrations/migration.rb +23 -0
  49. data/lib/volt/models/migrations/migration_runner.rb +146 -0
  50. data/lib/volt/models/model.rb +38 -1
  51. data/lib/volt/models/permissions.rb +8 -1
  52. data/lib/volt/models/persistors/array_store.rb +87 -8
  53. data/lib/volt/models/persistors/base.rb +19 -0
  54. data/lib/volt/models/persistors/model_store.rb +1 -1
  55. data/lib/volt/models/persistors/page.rb +4 -1
  56. data/lib/volt/models/persistors/query/query_identifier.rb +102 -0
  57. data/lib/volt/models/persistors/query/query_listener.rb +57 -12
  58. data/lib/volt/models/root_models/root_models.rb +19 -0
  59. data/lib/volt/models/url.rb +11 -2
  60. data/lib/volt/models/validations/validations.rb +5 -2
  61. data/lib/volt/models/validators/type_validator.rb +11 -0
  62. data/lib/volt/models/validators/unique_validator.rb +2 -2
  63. data/lib/volt/page/bindings/attribute_binding.rb +23 -1
  64. data/lib/volt/page/targets/attribute_section.rb +7 -0
  65. data/lib/volt/page/targets/binding_document/component_node.rb +44 -18
  66. data/lib/volt/page/targets/binding_document/tag_node.rb +41 -0
  67. data/lib/volt/page/tasks.rb +16 -8
  68. data/lib/volt/queries/live_query.rb +109 -0
  69. data/lib/volt/queries/live_query_pool.rb +58 -0
  70. data/lib/volt/queries/live_subquery.rb +0 -0
  71. data/lib/volt/queries/query_association_splitter.rb +31 -0
  72. data/lib/volt/queries/query_diff.rb +100 -0
  73. data/lib/volt/queries/query_runner.rb +110 -0
  74. data/lib/volt/queries/query_subscription.rb +80 -0
  75. data/lib/volt/queries/query_subscription_pool.rb +37 -0
  76. data/lib/volt/reactive/eventable.rb +8 -0
  77. data/lib/volt/reactive/reactive_array.rb +0 -4
  78. data/lib/volt/router/routes.rb +81 -31
  79. data/lib/volt/server/message_bus/base_message_bus.rb +9 -3
  80. data/lib/volt/server/message_bus/peer_to_peer.rb +6 -6
  81. data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +1 -1
  82. data/lib/volt/server/middleware/default_middleware_stack.rb +12 -8
  83. data/lib/volt/server/rack/component_paths.rb +31 -4
  84. data/lib/volt/server/rack/http_content_types.rb +62 -0
  85. data/lib/volt/server/rack/http_resource.rb +1 -1
  86. data/lib/volt/server/rack/index_files.rb +8 -1
  87. data/lib/volt/server/rack/opal_files.rb +16 -1
  88. data/lib/volt/server/rack/sprockets_helpers_setup.rb +32 -1
  89. data/lib/volt/server/socket_connection_handler.rb +16 -7
  90. data/lib/volt/server/template_handlers/sprockets_component_handler.rb +5 -3
  91. data/lib/volt/spec/capybara.rb +4 -3
  92. data/lib/volt/spec/setup.rb +5 -0
  93. data/lib/volt/tasks/dispatcher.rb +3 -1
  94. data/lib/volt/utils/data_transformer.rb +4 -4
  95. data/lib/volt/utils/ejson.rb +19 -6
  96. data/lib/volt/utils/promise_extensions.rb +1 -1
  97. data/lib/volt/utils/time_opal_patch.rb +749 -0
  98. data/lib/volt/utils/time_patch.rb +11 -4
  99. data/lib/volt/version.rb +1 -1
  100. data/lib/volt/volt/app.rb +19 -11
  101. data/lib/volt/volt/properties.rb +24 -0
  102. data/lib/volt/volt/server_setup/app.rb +30 -7
  103. data/lib/volt/volt/users.rb +15 -3
  104. data/spec/apps/kitchen_sink/Gemfile +5 -1
  105. data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -0
  106. data/spec/apps/kitchen_sink/app/main/controllers/save_controller.rb +1 -1
  107. data/spec/apps/kitchen_sink/app/main/controllers/server/simple_http_controller.rb +4 -0
  108. data/spec/apps/kitchen_sink/app/main/controllers/todos_controller.rb +4 -2
  109. data/spec/apps/kitchen_sink/app/main/models/post.rb +0 -1
  110. data/spec/apps/kitchen_sink/app/main/models/todo.rb +4 -0
  111. data/spec/apps/kitchen_sink/app/main/views/mailers/reset_password.html +10 -0
  112. data/spec/apps/kitchen_sink/app/main/views/todos/index.html +2 -0
  113. data/spec/apps/kitchen_sink/config/app.rb +2 -0
  114. data/spec/apps/migrations/config/db/migrations/1445111704_migration1.rb +7 -0
  115. data/spec/apps/migrations/config/db/migrations/1445113517_migration2.rb +7 -0
  116. data/spec/apps/migrations/config/db/migrations/1445115200_migration3.rb +7 -0
  117. data/spec/extra_core/class_spec.rb +10 -0
  118. data/spec/helpers/distance_spec.rb +35 -0
  119. data/spec/helpers/duration_spec.rb +160 -0
  120. data/spec/helpers/volt_time_spec.rb +275 -0
  121. data/spec/integration/callbacks_spec.rb +2 -1
  122. data/spec/integration/http_endpoints_spec.rb +4 -0
  123. data/spec/integration/save_spec.rb +1 -1
  124. data/spec/integration/todos_spec.rb +7 -5
  125. data/spec/models/array_model_spec.rb +17 -3
  126. data/spec/models/associations_spec.rb +48 -1
  127. data/spec/models/field_helpers_spec.rb +7 -3
  128. data/spec/models/migrations/migration_runner_spec.rb +69 -0
  129. data/spec/models/model_spec.rb +42 -8
  130. data/spec/models/permissions_spec.rb +20 -8
  131. data/spec/models/persistors/array_store_spec.rb +18 -0
  132. data/spec/models/persistors/page_spec.rb +15 -10
  133. data/spec/models/persistors/store_spec.rb +13 -3
  134. data/spec/models/url_spec.rb +4 -3
  135. data/spec/models/user_spec.rb +6 -3
  136. data/spec/models/user_validation_spec.rb +3 -3
  137. data/spec/models/validations_spec.rb +4 -0
  138. data/spec/models/validators/block_validations_spec.rb +9 -5
  139. data/spec/models/validators/email_validator_spec.rb +2 -0
  140. data/spec/models/validators/lifecycle_callbacks_spec.rb +86 -0
  141. data/spec/models/validators/unique_validator_spec.rb +1 -0
  142. data/spec/page/path_string_renderer_spec.rb +5 -0
  143. data/spec/queries/live_query_spec.rb +16 -0
  144. data/spec/queries/query_association_splitter_spec.rb +14 -0
  145. data/spec/queries/query_diff_spec.rb +132 -0
  146. data/spec/queries/query_identifier_spec.rb +98 -0
  147. data/spec/queries/query_runner_spec.rb +63 -0
  148. data/spec/queries/query_tracker_spec.rb +141 -0
  149. data/spec/router/routes_spec.rb +52 -21
  150. data/spec/server/middleware/rack_content_types_spec.rb +78 -0
  151. data/spec/server/rack/asset_files_spec.rb +38 -30
  152. data/spec/spec_helper.rb +8 -0
  153. data/spec/utils/ejson_spec.rb +9 -8
  154. data/spec/utils/ejson_volt_time_spec.rb +65 -0
  155. data/templates/migration/migration.rb.tt +9 -0
  156. data/templates/newgem/gitignore.tt +1 -0
  157. data/templates/project/Gemfile.tt +19 -2
  158. data/templates/project/README.md.tt +6 -1
  159. data/templates/project/app/main/config/dependencies.rb +6 -0
  160. data/templates/project/config/app.rb.tt +18 -4
  161. data/volt.gemspec +2 -2
  162. metadata +73 -16
  163. data/app/volt/tasks/live_query/live_query_pool.rb +0 -48
  164. data/app/volt/tasks/live_query/query_tracker.rb +0 -92
  165. data/spec/tasks/live_query_spec.rb +0 -18
  166. data/spec/tasks/query_tasks.rb +0 -7
  167. data/spec/tasks/query_tracker_spec.rb +0 -145
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe Volt::QueryIdentifier do
4
+ let(:ident) { subject }
5
+ it 'should call first on ident' do
6
+ expect(ident.name.to_query).to eq(["c", "ident", "name"])
7
+ end
8
+
9
+ it 'should group according to method calls' do
10
+ expect((ident.name < 5).to_query).to eq(["c", ["c", "ident", "name"], "<", 5])
11
+ end
12
+
13
+ it 'should group & into a Volt::QueryOp' do
14
+ query = ((ident.lat > 80) & (ident.lng < 50))
15
+ expect(query.to_query).to eq(
16
+ [
17
+ "c",
18
+ ["c", ["c", "ident", "lat"], ">", 80],
19
+ "&",
20
+ ["c", ["c", "ident", "lng"], "<", 50]
21
+ ]
22
+ )
23
+ end
24
+
25
+ it 'should place the . correctly when coercing' do
26
+ query = (5 < ident.lat)
27
+ expect(query.to_query).to eq(["c", 5, "<", ["c", "ident", "lat"]])
28
+ end
29
+
30
+ it 'should group | into a Volt::QueryOp' do
31
+ query = ((ident.lat > 80) & (ident.lng < 50)) | (ident.name == 'Bob')
32
+ expect(query.to_query).to eq(
33
+ [
34
+ "c",
35
+ [
36
+ "c",
37
+ ["c", ["c", "ident", "lat"], ">", 80],
38
+ '&',
39
+ ["c",
40
+ ["c", "ident", "lng"], "<", 50]
41
+ ],
42
+ '|',
43
+ ["c", ["c", "ident", "name"], "==", "Bob"]
44
+ ]
45
+ )
46
+ end
47
+
48
+ it 'should handle negation with ~' do
49
+ query = ((ident.name == 'Ryan') & ~(ident.lat > 40))
50
+ expect(query.to_query).to eq(
51
+ [
52
+ "c",
53
+ ["c", ["c", "ident", "name"], "==", "Ryan"],
54
+ "&",
55
+ ["c",
56
+ ["c", ["c", "ident", "lat"], ">", 40],
57
+ "~"
58
+ ]
59
+ ]
60
+ )
61
+ end
62
+
63
+ it 'should handle arrays as call arguments' do
64
+ query = (ident.name == [1,2,3])
65
+ expect(query.to_query).to eq(["c", ["c", "ident", "name"], "==", ["a", 1, 2, 3]])
66
+ end
67
+
68
+ it 'should handle =~' do
69
+ query = (ident.name =~ 'Bob')
70
+ expect(query.to_query).to eq(["c", ["c", "ident", "name"], "=~", "Bob"])
71
+ end
72
+
73
+ # This code fails until the following is fixed:
74
+ # https://github.com/opal/opal/issues/1138
75
+ # it 'should handle !~' do
76
+ # query = (ident.name !~ 'Bob')
77
+ # expect(query.to_query).to eq(["c", ["c", "ident", "name"], "!~", "Bob"])
78
+ # end
79
+
80
+ it 'should handle addition and comparison' do
81
+ query = (ident.pounds + 10 < 20)
82
+ expect(query.to_query).to eq(
83
+ [
84
+ "c",
85
+ [
86
+ "c",
87
+ ["c", "ident", "pounds"],
88
+ "+",
89
+ 10
90
+ ],
91
+ "<",
92
+ 20
93
+ ]
94
+ )
95
+ end
96
+
97
+ it 'should handle method calls like max'
98
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ if RUBY_PLATFORM != 'opal'
4
+ class ::QPost < Volt::Model
5
+ has_many :q_comments
6
+ end
7
+
8
+ class ::QComment < Volt::Model
9
+ belongs_to :q_post
10
+ end
11
+
12
+ describe Volt::QueryRunner do
13
+ it 'should run queries' do
14
+ data_store = double('data store')
15
+
16
+ query = [[:where, {user_id: 5}]]
17
+
18
+ result = [{id: 1, user_id: 5, title: 'Some post'}]
19
+ expect(data_store).to receive(:query).with('q_posts', query).and_return(result)
20
+
21
+ query_runner = Volt::QueryRunner.new(data_store, 'q_posts', query)
22
+
23
+ expect(query_runner.run).to eq(result)
24
+ end
25
+
26
+ it 'should run sub queries' do
27
+ data_store = double('data store')
28
+
29
+ query = [[:where, {user_id: 5}], [:includes, :q_comments]]
30
+
31
+ result1 = [
32
+ {id: 1, user_id: 5, title: 'Some post'},
33
+ {id: 2, user_id: 5, title: 'Another Post'}
34
+ ]
35
+ expect(data_store).to receive(:query).with(:q_posts, [[:where, {user_id: 5}]])
36
+ .and_return(result1)
37
+
38
+ query2 = [[:where, {:q_post_id=>[1, 2]}]]
39
+
40
+ result2 = [
41
+ {id: 4, q_post_id: 1, body: 'Some comment'},
42
+ {id: 5, q_post_id: 1, body: 'Another comment'},
43
+ {id: 6, q_post_id: 2, body: 'The best comment'}
44
+ ]
45
+ expect(data_store).to receive(:query).with(:q_comments, query2)
46
+ .and_return(result2)
47
+
48
+ query_runner = Volt::QueryRunner.new(data_store, :q_posts, query)
49
+
50
+ result3 = [
51
+ {id: 1, user_id: 5, title: 'Some post', q_comments: [
52
+ {id: 4, q_post_id: 1, body: 'Some comment'},
53
+ {id: 5, q_post_id: 1, body: 'Another comment'}
54
+ ]},
55
+ {id: 2, user_id: 5, title: 'Another Post', q_comments: [
56
+ {id: 6, q_post_id: 2, body: 'The best comment'}
57
+ ]}
58
+ ]
59
+
60
+ expect(query_runner.run).to eq(result3)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,141 @@
1
+ # if RUBY_PLATFORM != 'opal'
2
+ # describe 'LiveQuery' do
3
+ # # LiveQueryStub behaves as the front-end would with the changes to a
4
+ # # live query. Instead of passing changes to the models to the front
5
+ # # end, the changes are applied locally, then can be checked to see if
6
+ # # the correct transitions have taken place.
7
+ # class LiveQueryStub
8
+ # attr_reader :collection, :query, :items
9
+ # def initialize
10
+ # @collection = '_items'
11
+ # @query = {}
12
+ # @items = []
13
+ # end
14
+
15
+ # def notify_removed(ids, skip_channel)
16
+ # # Remove the id's that need to be removed
17
+ # @items.reject! { |item| ids.include?(item[:id]) }
18
+ # end
19
+
20
+ # def notify_added(index, data, skip_channel)
21
+ # @items.insert(index, data)
22
+ # end
23
+
24
+ # def notify_moved(id, index, skip_channel)
25
+ # item = @items.find { |item| item[:id] == id }
26
+ # @items.delete(item)
27
+
28
+ # @items.insert(index, item)
29
+ # end
30
+
31
+ # def notify_changed(id, data, skip_channel)
32
+ # item = @items.find { |item| item[:id] == id }
33
+ # idx = @items.index(item)
34
+ # @items.delete(item)
35
+ # @items.insert(idx, data)
36
+ # end
37
+ # end
38
+
39
+ # before do
40
+ # # Setup a live query stub
41
+ # @live_query = LiveQueryStub.new
42
+ # data_store = double('volt/data store')
43
+
44
+ # # return an empty collection
45
+ # @items = []
46
+ # expect(data_store).to receive(:query).at_least(:once) { @items.dup }
47
+
48
+ # @query_tracker = QueryTracker.new(@live_query, data_store)
49
+ # @query_tracker.run
50
+ # end
51
+
52
+ # it 'should add items' do
53
+ # @items = [
54
+ # { id: 1, name: 'one' }
55
+ # ]
56
+
57
+ # expect(@live_query.items).to eq([])
58
+
59
+ # @query_tracker.run
60
+
61
+ # expect(@live_query.items).to eq(@items)
62
+ # end
63
+
64
+ # it 'should remove items' do
65
+ # @items = [
66
+ # { id: 1, name: 'one' },
67
+ # { id: 2, name: 'two' }
68
+ # ]
69
+ # @query_tracker.run
70
+ # expect(@live_query.items).to eq(@items)
71
+
72
+ # @items = [
73
+ # { id: 2, name: 'two' }
74
+ # ]
75
+ # @query_tracker.run
76
+ # expect(@live_query.items).to eq(@items)
77
+ # end
78
+
79
+ # it 'should move items' do
80
+ # @items = [
81
+ # { id: 1, name: 'one' },
82
+ # { id: 2, name: 'two' },
83
+ # { id: 3, name: 'three' }
84
+ # ]
85
+ # @query_tracker.run
86
+ # expect(@live_query.items).to eq(@items)
87
+
88
+ # @items = [
89
+ # { id: 2, name: 'two' },
90
+ # { id: 3, name: 'three' },
91
+ # { id: 1, name: 'one' }
92
+ # ]
93
+ # @query_tracker.run
94
+ # expect(@live_query.items).to eq(@items)
95
+ # end
96
+
97
+ # it 'should handle complex transforms' do
98
+ # @items = [
99
+ # { id: 1, name: 'one' },
100
+ # { id: 2, name: 'two' },
101
+ # { id: 3, name: 'three' },
102
+ # { id: 4, name: 'four' },
103
+ # { id: 5, name: 'five' }
104
+ # ]
105
+ # @query_tracker.run
106
+ # expect(@live_query.items).to eq(@items)
107
+
108
+ # @items = [
109
+ # { id: 7, name: 'seven' },
110
+ # { id: 4, name: 'four' },
111
+ # { id: 1, name: 'one' },
112
+ # { id: 5, name: 'five' },
113
+ # { id: 3, name: 'three' },
114
+ # { id: 6, name: 'five' }
115
+ # ]
116
+ # @query_tracker.run
117
+ # expect(@live_query.items).to eq(@items)
118
+ # end
119
+
120
+ # it 'should notify data hash has changed' do
121
+ # @items = [
122
+ # { id: 1, name: 'one' },
123
+ # { id: 2, name: 'two' },
124
+ # { id: 3, name: 'three' },
125
+ # { id: 4, name: 'four' },
126
+ # { id: 5, name: 'five' }
127
+ # ]
128
+ # @query_tracker.run
129
+ # @items = [
130
+ # { id: 1, name: 'some' },
131
+ # { id: 2, name: 'values' },
132
+ # { id: 3, name: 'have' },
133
+ # { id: 4, name: 'changed' },
134
+ # { id: 5, name: 'other' }
135
+ # ]
136
+ # expect(@live_query.items).to_not eq(@items)
137
+ # @query_tracker.run
138
+ # expect(@live_query.items).to eq(@items)
139
+ # end
140
+ # end
141
+ # end
@@ -63,18 +63,22 @@ describe Volt::Routes do
63
63
  end
64
64
 
65
65
  param_matches = @routes.instance_variable_get(:@param_matches)
66
- expect(param_matches[:client].map { |v| v[0] }).to eq([
67
- { view: 'blog' },
68
- { view: 'blog/show', id: nil },
69
- { view: 'blog/edit', id: nil },
70
- { view: 'blog/tag', tag: nil },
71
- { view: 'login', action: 'user', name: nil, id: nil }
72
- ])
73
-
74
- expect(param_matches[:get].map { |v| v[0] }).to eq([
75
- { controller: 'articles', action: 'index' },
76
- { controller: 'articles', action: 'show', id: nil }
77
- ])
66
+ expect(param_matches[:client].map { |v| v[0] }).to eq(
67
+ [
68
+ { view: 'blog' },
69
+ { view: 'blog/show', id: nil },
70
+ { view: 'blog/edit', id: nil },
71
+ { view: 'blog/tag', tag: nil },
72
+ { view: 'login', action: 'user', name: nil, id: nil }
73
+ ]
74
+ )
75
+
76
+ expect(param_matches[:get].map { |v| v[0] }).to eq(
77
+ [
78
+ { controller: 'articles', action: 'index' },
79
+ { controller: 'articles', action: 'show', id: nil }
80
+ ]
81
+ )
78
82
  end
79
83
 
80
84
  it 'should match routes' do
@@ -92,6 +96,10 @@ describe Volt::Routes do
92
96
  put '/people', controller: 'people', action: 'update'
93
97
  patch '/people/1', controller: 'people', action: 'update'
94
98
  delete '/people/2', controller: 'people', action: 'destroy'
99
+ client '/pics/new/{{ new_id }}/two', controller: 'pics', action: 'new'
100
+ client '/pics/{{ pic_id }}/view/one', controller: 'pics', action: 'view'
101
+ client '/pics/{{ *pic_id }}', controller: 'pics', action: 'show'
102
+ get '/wide_match/{{ *path_parts }}', controller: 'wide_match', action: 'show'
95
103
  end
96
104
 
97
105
  params = @routes.url_to_params('/blog')
@@ -122,7 +130,7 @@ describe Volt::Routes do
122
130
  expect(params).to eq(controller: 'articles', action: 'index')
123
131
 
124
132
  params = @routes.url_to_params(:post, '/articles')
125
- expect(params).to be_nil
133
+ expect(params).to eq(false)
126
134
 
127
135
  params = @routes.url_to_params(:post, '/comments')
128
136
  expect(params).to eq(controller: 'comments', action: 'create')
@@ -141,6 +149,29 @@ describe Volt::Routes do
141
149
 
142
150
  params = @routes.url_to_params(:put, '/articles/2/comments/9')
143
151
  expect(params).to eq(controller: 'comments', action: 'update', articles_id: '2', id: '9')
152
+
153
+ params = @routes.url_to_params('/pics/new/view/one')
154
+ expect(params).to eq({controller: "pics", action: "view", pic_id: "new"})
155
+
156
+ params = @routes.url_to_params('/pics/new/view/two')
157
+ expect(params).to eq({controller: "pics", action: "new", new_id: "view"})
158
+
159
+ params = @routes.url_to_params('/pics/new/view/three')
160
+ expect(params).to eq({controller: "pics", action: "show", pic_id: "new/view/three"})
161
+
162
+ params = @routes.url_to_params(:get, '/wide_match/some/image/path/file.png')
163
+ expect(params).to eq({controller: "wide_match", action: "show", path_parts: "some/image/path/file.png"})
164
+
165
+ params = @routes.url_to_params(:get, '/wide_match/http://something/cool.jpg')
166
+ expect(params).to eq({controller: "wide_match", action: "show", path_parts: "http://something/cool.jpg"})
167
+ end
168
+
169
+ it 'should raise an error if the splat match isn\'t at the end of the url' do
170
+ expect do
171
+ routes do
172
+ client '/blog/{{ *slug }}/after', view: 'blog'
173
+ end
174
+ end.to raise_error('The splat (*) operator can only be used at the end of a url')
144
175
  end
145
176
 
146
177
  it 'should go from params to url' do
@@ -279,16 +310,16 @@ describe Volt::Routes do
279
310
  params = @routes.url_to_params(:get, '/api/v1/articles/1')
280
311
  expect(params).to eq(controller: 'articles', action: 'show', id: '1')
281
312
 
282
- expect(@routes.url_to_params(:post, '/api/v1/articles')).to be_nil
283
- expect(@routes.url_to_params(:put, '/api/v1/articles/1')).to be_nil
284
- expect(@routes.url_to_params(:delete, '/api/v1/articles/1')).to be_nil
313
+ expect(@routes.url_to_params(:post, '/api/v1/articles')).to eq(false)
314
+ expect(@routes.url_to_params(:put, '/api/v1/articles/1')).to eq(false)
315
+ expect(@routes.url_to_params(:delete, '/api/v1/articles/1')).to eq(false)
285
316
 
286
317
  routes do
287
318
  rest '/api/v1/articles', controller: 'articles', only: [:update, :destroy, :create]
288
319
  end
289
320
 
290
- expect(@routes.url_to_params(:get, '/api/v1/articles')).to be_nil
291
- expect(@routes.url_to_params(:get, '/api/v1/articles/1')).to be_nil
321
+ expect(@routes.url_to_params(:get, '/api/v1/articles')).to eq(false)
322
+ expect(@routes.url_to_params(:get, '/api/v1/articles/1')).to eq(false)
292
323
 
293
324
  params = @routes.url_to_params(:post, '/api/v1/articles')
294
325
  expect(params).to eq(controller: 'articles', action: 'create')
@@ -311,8 +342,8 @@ describe Volt::Routes do
311
342
  params = @routes.url_to_params(:get, '/api/v1/articles/1')
312
343
  expect(params).to eq(controller: 'articles', action: 'show', id: '1')
313
344
 
314
- expect(@routes.url_to_params(:post, '/api/v1/articles')).to be_nil
315
- expect(@routes.url_to_params(:put, '/api/v1/articles/1')).to be_nil
316
- expect(@routes.url_to_params(:delete, '/api/v1/articles/1')).to be_nil
345
+ expect(@routes.url_to_params(:post, '/api/v1/articles')).to eq(false)
346
+ expect(@routes.url_to_params(:put, '/api/v1/articles/1')).to eq(false)
347
+ expect(@routes.url_to_params(:delete, '/api/v1/articles/1')).to eq(false)
317
348
  end
318
349
  end
@@ -0,0 +1,78 @@
1
+ if RUBY_PLATFORM != 'opal'
2
+ require 'spec_helper'
3
+
4
+ describe Rack::HttpContentTypes do
5
+ include Rack::Test::Methods
6
+
7
+ let(:app) { Volt.current_app.middleware }
8
+
9
+ describe 'with default parser' do
10
+ it "allows you to setup parsers for content types" do
11
+ middleware = Rack::HttpContentTypes.new Volt, :parsers => { 'foo' => 'bar' }
12
+ expect(middleware.parsers['foo']).to eq('bar')
13
+ end
14
+
15
+ it "allows you to setup error handlers" do
16
+ middleware = Rack::HttpContentTypes.new Volt, :handlers => { 'foo' => 'bar' }
17
+ expect(middleware.handlers['foo']).to eq('bar')
18
+ end
19
+
20
+ it "parses params from Content-Type: application/json" do
21
+ payload = JSON.dump(:a => 1)
22
+ post '/simple_http', payload, { 'CONTENT_TYPE' => 'application/json' }
23
+ expect(last_response).to be_ok
24
+ expect(last_response.body).to match(/a: 1/)
25
+ end
26
+
27
+ it "does not handle params from unknown Content-type" do
28
+ payload = JSON.dump(:a => 1)
29
+ post '/simple_http', payload, { 'CONTENT_TYPE' => 'application/unknown' }
30
+ expect(last_response).to be_ok
31
+ expect(last_response.body).to_not match(/a: 1/)
32
+ end
33
+
34
+ it "matches Content-Type by regex" do
35
+ payload = JSON.dump(:a => 1)
36
+ post '/simple_http', payload, { 'CONTENT_TYPE' => 'application/vnd.foo+json' }
37
+ expect(last_response).to be_ok
38
+ expect(last_response.body).to match(/a: 1/)
39
+ end
40
+
41
+ it "handles custom json parser" do
42
+ Volt.setup do |config|
43
+ config.http_content_types = {
44
+ parsers:{
45
+ 'application/json' => proc { |body| {'rick_says' => 'never gonna let you down'} }
46
+ }
47
+ }
48
+ end
49
+ payload = JSON.dump(:a => 1)
50
+ post '/simple_http', payload, { 'CONTENT_TYPE' => 'application/json' }
51
+ expect(last_response).to be_ok
52
+ expect(last_response.body).to match(/never gonna let you down/)
53
+ end
54
+ end
55
+
56
+ describe 'with custom parser' do
57
+ before do
58
+ Volt.setup do |config|
59
+ config.http_content_types = {
60
+ parsers: {
61
+ 'application/roll' => proc { |body| {'rick_says' => 'never gonna give you up'}}
62
+ }
63
+ }
64
+ end
65
+ end
66
+
67
+ it "handles custom content types" do
68
+ #see spec/apps/kitchen_sink/config/app.rb
69
+ payload = JSON.dump(:a => 1)
70
+ post '/simple_http', payload, { 'CONTENT_TYPE' => 'application/roll' }
71
+ expect(last_response).to be_ok
72
+ expect(last_response.body).to match(/never gonna give you up/)
73
+ end
74
+ end
75
+
76
+
77
+ end
78
+ end