volt 0.9.6 → 0.9.7.pre2

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 (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