flash_messenger 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 (85) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +46 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.rdoc +3 -0
  8. data/Rakefile +26 -0
  9. data/app/assets/images/flash_messenger/.keep +0 -0
  10. data/app/assets/stylesheets/flash_messenger/.keep +0 -0
  11. data/app/controllers/application_controller.rb +39 -0
  12. data/app/helpers/.keep +0 -0
  13. data/app/mailers/.keep +0 -0
  14. data/app/models/.keep +0 -0
  15. data/app/views/.keep +0 -0
  16. data/bin/rails +12 -0
  17. data/config/locales/en-US.yml +28 -0
  18. data/config/routes.rb +3 -0
  19. data/flash_messenger.gemspec +32 -0
  20. data/lib/flash_messenger.rb +9 -0
  21. data/lib/flash_messenger/controller_injection.rb +45 -0
  22. data/lib/flash_messenger/engine.rb +14 -0
  23. data/lib/flash_messenger/messages/base.rb +174 -0
  24. data/lib/flash_messenger/messages/nonpersistent.rb +9 -0
  25. data/lib/flash_messenger/messages/persistent.rb +9 -0
  26. data/lib/flash_messenger/messenger.rb +25 -0
  27. data/lib/flash_messenger/storage.rb +141 -0
  28. data/lib/flash_messenger/version.rb +3 -0
  29. data/lib/tasks/flash_messenger_tasks.rake +4 -0
  30. data/spec/dummy/README.rdoc +28 -0
  31. data/spec/dummy/Rakefile +6 -0
  32. data/spec/dummy/app/assets/images/.keep +0 -0
  33. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  34. data/spec/dummy/app/assets/javascripts/index.js +2 -0
  35. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  36. data/spec/dummy/app/assets/stylesheets/index.css +4 -0
  37. data/spec/dummy/app/controllers/application_controller.rb +7 -0
  38. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  39. data/spec/dummy/app/controllers/index_controller.rb +6 -0
  40. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  41. data/spec/dummy/app/helpers/index_helper.rb +2 -0
  42. data/spec/dummy/app/mailers/.keep +0 -0
  43. data/spec/dummy/app/models/.keep +0 -0
  44. data/spec/dummy/app/models/concerns/.keep +0 -0
  45. data/spec/dummy/app/views/index/index.html.erb +5 -0
  46. data/spec/dummy/app/views/layouts/application.html.erb +13 -0
  47. data/spec/dummy/bin/bundle +3 -0
  48. data/spec/dummy/bin/rails +4 -0
  49. data/spec/dummy/bin/rake +4 -0
  50. data/spec/dummy/config.ru +4 -0
  51. data/spec/dummy/config/application.rb +22 -0
  52. data/spec/dummy/config/boot.rb +5 -0
  53. data/spec/dummy/config/database.yml +25 -0
  54. data/spec/dummy/config/environment.rb +5 -0
  55. data/spec/dummy/config/environments/development.rb +37 -0
  56. data/spec/dummy/config/environments/production.rb +78 -0
  57. data/spec/dummy/config/environments/test.rb +39 -0
  58. data/spec/dummy/config/initializers/assets.rb +8 -0
  59. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  60. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  61. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  62. data/spec/dummy/config/initializers/inflections.rb +16 -0
  63. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  64. data/spec/dummy/config/initializers/session_store.rb +3 -0
  65. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  66. data/spec/dummy/config/locales/en.yml +23 -0
  67. data/spec/dummy/config/routes.rb +56 -0
  68. data/spec/dummy/config/secrets.yml +22 -0
  69. data/spec/dummy/lib/assets/.keep +0 -0
  70. data/spec/dummy/public/404.html +67 -0
  71. data/spec/dummy/public/422.html +67 -0
  72. data/spec/dummy/public/500.html +66 -0
  73. data/spec/dummy/public/favicon.ico +0 -0
  74. data/spec/dummy/spec/controllers/index_controller_spec.rb +5 -0
  75. data/spec/dummy/spec/helpers/index_helper_spec.rb +15 -0
  76. data/spec/examples/shared_examples.rb +27 -0
  77. data/spec/features/messages/base_spec.rb +102 -0
  78. data/spec/features/messages/nonpersistent_spec.rb +46 -0
  79. data/spec/features/messages/persistent_spec.rb +46 -0
  80. data/spec/features/messenger_spec.rb +96 -0
  81. data/spec/features/storage_spec.rb +152 -0
  82. data/spec/rails_helper.rb +50 -0
  83. data/spec/spec_helper.rb +92 -0
  84. data/spec/support/shared_examples.rb +26 -0
  85. metadata +309 -0
File without changes
@@ -0,0 +1,5 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe IndexController, :type => :controller do
4
+
5
+ end
@@ -0,0 +1,15 @@
1
+ require 'rails_helper'
2
+
3
+ # Specs in this file have access to a helper object that includes
4
+ # the IndexHelper. For example:
5
+ #
6
+ # describe IndexHelper do
7
+ # describe "string concat" do
8
+ # it "concats two strings with spaces" do
9
+ # expect(helper.concat_strings("this","that")).to eq("this that")
10
+ # end
11
+ # end
12
+ # end
13
+ RSpec.describe IndexHelper, :type => :helper do
14
+ pending "add some examples to (or delete) #{__FILE__}"
15
+ end
@@ -0,0 +1,27 @@
1
+
2
+ # These shared example test that a subject's accessor method is:
3
+ #
4
+ # A) Publicly exposed
5
+ # B) Not nil
6
+ # c) Result "equal" to the `let` with the same name in context
7
+ #
8
+ # @param [Symbol] Method name as symbol
9
+ # @param [*args] Arbitrary arguments to pass to the `send` call
10
+ #
11
+ RSpec.shared_examples 'a public accessor method' do |target, *args|
12
+ let(:result) do
13
+ subject.public_send(target, *(args.map { |i| public_send(i) }))
14
+ end
15
+
16
+ let(:expected) do
17
+ public_send(target)
18
+ end
19
+
20
+ it "publicly exposes ##{target}" do
21
+ expect(result).not_to be_nil
22
+ end
23
+
24
+ it 'has expected values' do
25
+ expect(result).to eq(expected)
26
+ end
27
+ end
@@ -0,0 +1,102 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.shared_examples 'a helper which yields message of kind' do |klass, target, *args|
4
+ let(:klazz) { public_send(klass) }
5
+
6
+ let(:instance) do
7
+ subject.public_send(target, *(args.map { |i| public_send(i) }))
8
+ end
9
+
10
+ it_behaves_like 'a message instance of kind', :klazz, :instance
11
+ end
12
+
13
+ RSpec.shared_examples 'a message instance of kind' do |klass, target|
14
+ let(:kind) { public_send(klass) }
15
+ let(:victim) { public_send(target) }
16
+
17
+ it "returns an instance of #{klass}" do
18
+ expect(victim).to be_a(kind)
19
+ end
20
+
21
+ context '#serialization' do
22
+ it 'serializes and deserializes properly' do
23
+ expect(victim.to_session).to be_a(String)
24
+
25
+ another_victim = victim.class.from_session(victim.to_session)
26
+
27
+ expect(another_victim).to eq(victim)
28
+ end
29
+ end
30
+
31
+ # Note: inherits default_message from calling context
32
+ context '#message' do
33
+ it 'has the expected message' do
34
+ expect(victim.message).to eq(default_message)
35
+ end
36
+ end
37
+
38
+ context '#eql?' do
39
+ it 'equals another message instance with the same string' do
40
+ another_victim = victim.dup
41
+ expect(another_victim).to eq(victim)
42
+ expect(another_victim.__id__).not_to eq(victim.__id__)
43
+ end
44
+ end
45
+
46
+ context '#match?' do
47
+ it 'matches the string value' do
48
+ expect(victim).to match(victim.message)
49
+ end
50
+ end
51
+
52
+ context '#type?' do
53
+ it 'exposes its type helper properly' do
54
+ expect(victim.public_send("#{victim.level}?")).to be_truthy
55
+ end
56
+ end
57
+ end
58
+
59
+ RSpec.describe FlashMessenger::Messages::Base do
60
+ subject { FlashMessenger::Messages::Base }
61
+
62
+ let(:default_translation) { 'development.lorem_ipsum_1' }
63
+ let(:default_message) { I18n.t(default_translation) }
64
+ let(:default_level) { :notice }
65
+ let(:default_params) { { test: 'foo' } }
66
+
67
+ context 'with vanilla messages' do
68
+ let(:new_with_message) do
69
+ subject.new(default_level, default_message, default_params)
70
+ end
71
+
72
+ context '#new' do
73
+ it 'returns a new FlashMessenger::Messages::Nonpersistent object' do
74
+ expect(new_with_message).to be_a(subject)
75
+ end
76
+
77
+ it 'is defines the interface' do
78
+ expect { new_with_message.persistent? }.to raise_error(NotImplementedError)
79
+ end
80
+
81
+ it_behaves_like 'a message instance of kind', :subject, :new_with_message
82
+ end
83
+ end
84
+
85
+ context 'with i18n translations' do
86
+ let(:new_with_translation) do
87
+ subject.new(default_level, default_translation, default_params)
88
+ end
89
+
90
+ context '#new' do
91
+ it 'returns a new FlashMessenger::Messages::Nonpersistent object' do
92
+ expect(new_with_translation).to be_a(subject)
93
+ end
94
+
95
+ it 'is defines the interface' do
96
+ expect { new_with_translation.persistent? }.to raise_error(NotImplementedError)
97
+ end
98
+
99
+ it_behaves_like 'a message instance of kind', :subject, :new_with_translation
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,46 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe FlashMessenger::Messages::Nonpersistent do
4
+ subject { FlashMessenger::Messages::Nonpersistent }
5
+
6
+ let(:default_translation) { 'development.lorem_ipsum_1' }
7
+ let(:default_message) { I18n.t(default_translation) }
8
+ let(:default_level) { :notice }
9
+ let(:default_params) { { test: 'foo' } }
10
+
11
+ context 'with vanilla messages' do
12
+ let(:new_with_message) do
13
+ subject.new(default_level, default_message, default_params)
14
+ end
15
+
16
+ context '#new' do
17
+ it 'returns a new FlashMessenger::Messages::Nonpersistent object' do
18
+ expect(new_with_message).to be_a(subject)
19
+ end
20
+
21
+ it 'is not persistent' do
22
+ expect(new_with_message.persistent?).to be_falsy
23
+ end
24
+
25
+ it_behaves_like 'a message instance of kind', :subject, :new_with_message
26
+ end
27
+ end
28
+
29
+ context 'with i18n translations' do
30
+ let(:new_with_translation) do
31
+ subject.new(default_level, default_translation, default_params)
32
+ end
33
+
34
+ context '#new' do
35
+ it 'returns a new FlashMessenger::Messages::Nonpersistent object' do
36
+ expect(new_with_translation).to be_a(subject)
37
+ end
38
+
39
+ it 'is not persistent' do
40
+ expect(new_with_translation.persistent?).to be_falsy
41
+ end
42
+
43
+ it_behaves_like 'a message instance of kind', :subject, :new_with_translation
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,46 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe FlashMessenger::Messages::Persistent do
4
+ subject { FlashMessenger::Messages::Persistent }
5
+
6
+ let(:default_translation) { 'development.lorem_ipsum_1' }
7
+ let(:default_message) { I18n.t(default_translation) }
8
+ let(:default_level) { :notice }
9
+ let(:default_params) { { test: 'foo' } }
10
+
11
+ context 'with vanilla messages' do
12
+ let(:new_with_message) do
13
+ subject.new(default_level, default_message, default_params)
14
+ end
15
+
16
+ context '#new' do
17
+ it 'returns a new FlashMessenger::Messages::Persistent object' do
18
+ expect(new_with_message).to be_a(subject)
19
+ end
20
+
21
+ it 'is persistent' do
22
+ expect(new_with_message.persistent?).to be_truthy
23
+ end
24
+
25
+ it_behaves_like 'a message instance of kind', :subject, :new_with_message
26
+ end
27
+ end
28
+
29
+ context 'with i18n translations' do
30
+ let(:new_with_translation) do
31
+ subject.new(default_level, default_translation, default_params)
32
+ end
33
+
34
+ context '#new' do
35
+ it 'returns a new FlashMessenger::Messages::Persistent object' do
36
+ expect(new_with_translation).to be_a(subject)
37
+ end
38
+
39
+ it 'is persistent' do
40
+ expect(new_with_translation.persistent?).to be_truthy
41
+ end
42
+
43
+ it_behaves_like 'a message instance of kind', :subject, :new_with_translation
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,96 @@
1
+ require 'pry'
2
+ require 'spec_helper'
3
+
4
+ RSpec.describe FlashMessenger, js: true do
5
+ subject { FlashMessenger }
6
+
7
+ let(:nonpersistent_message_klass) { FlashMessenger::Messages::Nonpersistent }
8
+ let(:persistent_message_klass) { FlashMessenger::Messages::Persistent }
9
+
10
+ let(:default_klass) { FlashMessenger::DEFAULT_MESSAGE_KLASS }
11
+ let(:default_translation) { 'development.lorem_ipsum_1' }
12
+ let(:default_message) { I18n.t(default_translation) }
13
+ let(:default_level) { :notice }
14
+ let(:default_params) { { test: 'foo' } }
15
+
16
+ context '#new' do
17
+ it 'returns a new FlashMessenger::Storage object' do
18
+ expect(subject.new).to be_a(FlashMessenger::Storage)
19
+ end
20
+
21
+ it 'with an empty message array' do
22
+ expect(subject.new.messages).to be_a(Array)
23
+ expect(subject.new.messages).to be_empty
24
+ end
25
+ end
26
+
27
+ context '#alert' do
28
+ let(:alert) { default_klass.alert(default_message) }
29
+
30
+ it_behaves_like 'a public accessor method',
31
+ :alert,
32
+ :default_message
33
+
34
+ it_behaves_like 'a helper which yields message of kind', :default_klass,
35
+ :alert,
36
+ :default_message
37
+ end
38
+
39
+ context '#error' do
40
+ let(:error) { default_klass.error(default_message) }
41
+
42
+ it_behaves_like 'a public accessor method',
43
+ :error,
44
+ :default_message
45
+
46
+ it_behaves_like 'a helper which yields message of kind', :default_klass,
47
+ :error,
48
+ :default_message
49
+ end
50
+
51
+ context '#info' do
52
+ let(:info) { default_klass.info(default_message) }
53
+
54
+ it_behaves_like 'a public accessor method',
55
+ :info,
56
+ :default_message
57
+
58
+ it_behaves_like 'a helper which yields message of kind', :default_klass,
59
+ :info,
60
+ :default_message
61
+ end
62
+
63
+ context '#notice' do
64
+ let(:notice) { default_klass.notice(default_message) }
65
+
66
+ it_behaves_like 'a public accessor method',
67
+ :notice,
68
+ :default_message
69
+
70
+ it_behaves_like 'a helper which yields message of kind', :default_klass,
71
+ :notice,
72
+ :default_message
73
+ end
74
+
75
+ context 'during user session' do
76
+ let(:flash_messenger) { FlashMessenger.new }
77
+
78
+ def cycle_messages(flash_messenger)
79
+ flash_messenger.each_message { |i| puts i }
80
+ end
81
+
82
+ it 'persists :persistent messages' do
83
+ flash_messenger.error "It is currently #{DateTime.now}.", :persistent
84
+
85
+ expect { cycle_messages(flash_messenger) }.not_to \
86
+ change { flash_messenger.messages.size }
87
+ end
88
+
89
+ it 'does not persist :nonpersistent messages' do
90
+ flash_messenger.error "It is currently #{DateTime.now}."
91
+
92
+ expect { cycle_messages(flash_messenger) }.to \
93
+ change { flash_messenger.messages.size }.by(-1)
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,152 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe FlashMessenger::Storage do
4
+ subject { FlashMessenger::Storage.new }
5
+
6
+ let(:nonpersistent_message_klass) { FlashMessenger::Messages::Nonpersistent }
7
+ let(:persistent_message_klass) { FlashMessenger::Messages::Persistent }
8
+
9
+ let(:default_klass) { nonpersistent_message_klass }
10
+ let(:default_translation) { 'development.lorem_ipsum_1' }
11
+ let(:default_message) { I18n.t(default_translation) }
12
+ let(:default_level) { :notice }
13
+ let(:default_params) { { test: 'foo' } }
14
+
15
+ let(:first_message) { subject.messages.first }
16
+ let(:second_message) { subject.messages[1] }
17
+ let(:third_message) { subject.messages[2] }
18
+ let(:last_message) { subject.messages.last }
19
+
20
+ context '#new' do
21
+ it 'returns a new FlashMessenger::Storage object' do
22
+ expect(subject).to be_a(FlashMessenger::Storage)
23
+ end
24
+
25
+ it 'with an empty message array' do
26
+ expect(subject.messages).to be_a(Array)
27
+ expect(subject.messages).to be_empty
28
+ end
29
+ end
30
+
31
+ context '#alert' do
32
+ let(:alert) { default_klass.alert(default_message) }
33
+
34
+ it_behaves_like 'a public accessor method',
35
+ :alert,
36
+ :default_message
37
+
38
+ it_behaves_like 'a helper which yields message of kind', :default_klass,
39
+ :alert,
40
+ :default_message
41
+ end
42
+
43
+ context '#error' do
44
+ let(:error) { default_klass.error(default_message) }
45
+
46
+ it_behaves_like 'a public accessor method',
47
+ :error,
48
+ :default_message
49
+
50
+ it_behaves_like 'a helper which yields message of kind', :default_klass,
51
+ :error,
52
+ :default_message
53
+ end
54
+
55
+ context '#info' do
56
+ let(:info) { default_klass.info(default_message) }
57
+
58
+ it_behaves_like 'a public accessor method',
59
+ :info,
60
+ :default_message
61
+
62
+ it_behaves_like 'a helper which yields message of kind', :default_klass,
63
+ :info,
64
+ :default_message
65
+ end
66
+
67
+ context '#notice' do
68
+ let(:notice) { default_klass.notice(default_message) }
69
+
70
+ it_behaves_like 'a public accessor method',
71
+ :notice,
72
+ :default_message
73
+
74
+ it_behaves_like 'a helper which yields message of kind', :default_klass,
75
+ :notice,
76
+ :default_message
77
+ end
78
+
79
+ context '#each' do
80
+ let(:nonpersistent_message) { nonpersistent_message_klass.alert(default_message) }
81
+ let(:persistent_message) { persistent_message_klass.alert(default_message) }
82
+
83
+ it 'records all messages' do
84
+ subject << nonpersistent_message
85
+ subject << persistent_message
86
+ expect(first_message).to match(nonpersistent_message.message)
87
+ expect(second_message).to match(persistent_message.message)
88
+ end
89
+
90
+ it 'does not allow duplicate messages of same type / level' do
91
+ expect(subject.messages).to be_empty
92
+ subject << persistent_message
93
+ subject << persistent_message
94
+ subject << nonpersistent_message
95
+ subject << nonpersistent_message
96
+ expect(subject.messages.size).to eq(2)
97
+ end
98
+
99
+ it 'iterates through all messages and persists the persistent messages' do
100
+ subject << nonpersistent_message
101
+ subject << persistent_message
102
+ read_messages = []
103
+ subject.each_message do |message|
104
+ read_messages << message
105
+ end
106
+ expect(read_messages).to include(nonpersistent_message)
107
+ expect(read_messages).to include(persistent_message)
108
+ expect(subject.messages.size).to eq(1)
109
+ expect(first_message).to eq(persistent_message)
110
+ end
111
+ end
112
+
113
+ context '#serialization' do
114
+ let(:nonpersistent_message) { nonpersistent_message_klass.alert(default_message) }
115
+ let(:persistent_message) { persistent_message_klass.alert(default_message) }
116
+
117
+ let(:expected_json) do
118
+ {
119
+ "locale" => "en-US",
120
+ "messages" => [
121
+ {
122
+ "i18n_params" => { "raise" => true },
123
+ "level" => "alert",
124
+ "translation" => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id lobortis tortor. Nam cursus pharetra purus non elementum. Sed eu libero leo. Aliquam eget justo vel odio consectetur facilisis id a sapien. Duis pulvinar tincidunt suscipit. Quisque volutpat justo vitae fringilla lacinia. Aenean semper, nulla at mattis sagittis, purus felis aliquet lorem, sit amet suscipit dolor elit nec tellus. Pellentesque interdum nulla maximus massa elementum, at posuere augue scelerisque.",
125
+ "class" => "nonpersistent"
126
+ },
127
+ {
128
+ "i18n_params" => { "raise" => true },
129
+ "level" => "alert",
130
+ "translation" => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id lobortis tortor. Nam cursus pharetra purus non elementum. Sed eu libero leo. Aliquam eget justo vel odio consectetur facilisis id a sapien. Duis pulvinar tincidunt suscipit. Quisque volutpat justo vitae fringilla lacinia. Aenean semper, nulla at mattis sagittis, purus felis aliquet lorem, sit amet suscipit dolor elit nec tellus. Pellentesque interdum nulla maximus massa elementum, at posuere augue scelerisque.",
131
+ "class" => "persistent"
132
+ }
133
+ ]
134
+ }.to_json
135
+ end
136
+
137
+ it 'serializes itself and messages' do
138
+ subject << nonpersistent_message
139
+ subject << persistent_message
140
+ expect(subject.to_session).to eq(expected_json)
141
+ end
142
+
143
+ it 'deserializes itself and messages' do
144
+ subject << nonpersistent_message
145
+ subject << persistent_message
146
+ deserialized_instance = subject.class.from_session(expected_json)
147
+ expect(deserialized_instance.messages.size).to eq(2)
148
+ expect(deserialized_instance.messages.first.persistent?).to be_falsy
149
+ expect(deserialized_instance.messages.last.persistent?).to be_truthy
150
+ end
151
+ end
152
+ end