gaq 0.2.0

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 (70) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +15 -0
  3. data/Guardfile +23 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +102 -0
  6. data/Rakefile +1 -0
  7. data/gaq.gemspec +22 -0
  8. data/lib/gaq.rb +3 -0
  9. data/lib/gaq/class_cache.rb +32 -0
  10. data/lib/gaq/command_language.rb +145 -0
  11. data/lib/gaq/configuration.rb +159 -0
  12. data/lib/gaq/controller_facade.rb +15 -0
  13. data/lib/gaq/controller_handle.rb +93 -0
  14. data/lib/gaq/dsl_target.rb +51 -0
  15. data/lib/gaq/dsl_target_factory.rb +64 -0
  16. data/lib/gaq/flash_commands_adapter.rb +48 -0
  17. data/lib/gaq/interprets_config.rb +13 -0
  18. data/lib/gaq/railtie.rb +40 -0
  19. data/lib/gaq/snippet_renderer.rb +44 -0
  20. data/lib/gaq/version.rb +3 -0
  21. data/spec-dummy/.rspec +1 -0
  22. data/spec-dummy/README.rdoc +261 -0
  23. data/spec-dummy/Rakefile +7 -0
  24. data/spec-dummy/app/assets/images/rails.png +0 -0
  25. data/spec-dummy/app/assets/javascripts/application.js +13 -0
  26. data/spec-dummy/app/assets/stylesheets/application.css +13 -0
  27. data/spec-dummy/app/controllers/application_controller.rb +3 -0
  28. data/spec-dummy/app/controllers/integration_spec_controller.rb +22 -0
  29. data/spec-dummy/app/helpers/application_helper.rb +2 -0
  30. data/spec-dummy/app/views/integration_spec/view.erb +0 -0
  31. data/spec-dummy/app/views/layouts/application.html.erb +16 -0
  32. data/spec-dummy/config.ru +4 -0
  33. data/spec-dummy/config/application.rb +64 -0
  34. data/spec-dummy/config/boot.rb +6 -0
  35. data/spec-dummy/config/environment.rb +5 -0
  36. data/spec-dummy/config/environments/development.rb +26 -0
  37. data/spec-dummy/config/environments/production.rb +51 -0
  38. data/spec-dummy/config/environments/test_dynamic.rb +39 -0
  39. data/spec-dummy/config/environments/test_static.rb +38 -0
  40. data/spec-dummy/config/initializers/backtrace_silencers.rb +7 -0
  41. data/spec-dummy/config/initializers/inflections.rb +15 -0
  42. data/spec-dummy/config/initializers/mime_types.rb +5 -0
  43. data/spec-dummy/config/initializers/secret_token.rb +7 -0
  44. data/spec-dummy/config/initializers/session_store.rb +8 -0
  45. data/spec-dummy/config/initializers/wrap_parameters.rb +10 -0
  46. data/spec-dummy/config/locales/en.yml +5 -0
  47. data/spec-dummy/config/routes.rb +8 -0
  48. data/spec-dummy/db/seeds.rb +7 -0
  49. data/spec-dummy/public/404.html +26 -0
  50. data/spec-dummy/public/422.html +26 -0
  51. data/spec-dummy/public/500.html +25 -0
  52. data/spec-dummy/public/favicon.ico +0 -0
  53. data/spec-dummy/public/robots.txt +5 -0
  54. data/spec-dummy/script/rails +6 -0
  55. data/spec-dummy/spec/common_spec_methods.rb +88 -0
  56. data/spec-dummy/spec/features/dynamic_config_spec.rb +21 -0
  57. data/spec-dummy/spec/features/next_request_spec.rb +27 -0
  58. data/spec-dummy/spec/features/presence_spec.rb +64 -0
  59. data/spec-dummy/spec/spec_helper.rb +41 -0
  60. data/spec/lib/gaq/class_cache_spec.rb +62 -0
  61. data/spec/lib/gaq/command_language_spec.rb +267 -0
  62. data/spec/lib/gaq/configuration_spec.rb +233 -0
  63. data/spec/lib/gaq/controller_facade_spec.rb +29 -0
  64. data/spec/lib/gaq/controller_handle_spec.rb +510 -0
  65. data/spec/lib/gaq/dsl_target_factory_spec.rb +163 -0
  66. data/spec/lib/gaq/dsl_target_spec.rb +87 -0
  67. data/spec/lib/gaq/flash_commands_adapter_spec.rb +116 -0
  68. data/spec/lib/gaq/interprets_config_spec.rb +37 -0
  69. data/spec/lib/gaq/snippet_renderer_spec.rb +60 -0
  70. metadata +159 -0
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/422.html -->
21
+ <div class="dialog">
22
+ <h1>The change you wanted was rejected.</h1>
23
+ <p>Maybe you tried to change something you didn't have access to.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/500.html -->
21
+ <div class="dialog">
22
+ <h1>We're sorry, but something went wrong.</h1>
23
+ </div>
24
+ </body>
25
+ </html>
File without changes
@@ -0,0 +1,5 @@
1
+ # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
2
+ #
3
+ # To ban all spiders from the entire site uncomment the next two lines:
4
+ # User-Agent: *
5
+ # Disallow: /
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,88 @@
1
+ require 'nokogiri'
2
+
3
+ module Helpers
4
+ def gaq_cdata
5
+ html = Nokogiri::HTML.parse(page.body)
6
+
7
+ html.css('script[type="text/javascript"]').find do |script|
8
+ cdata = script.children.find(&:cdata?) \
9
+ and cdata.text.include?('_gaq') \
10
+ and break(cdata)
11
+ end
12
+ end
13
+
14
+ def gaq_cdata_content
15
+ /<!\[CDATA\[(.*)\]\]>/m.match(gaq_cdata)[1]
16
+ end
17
+
18
+ def gaq_split_at_snippet_beginning
19
+ text_lines_without_comments = gaq_cdata_content.split("\n").map do |line|
20
+ if me = %r{^(.*?)//}.match(line)
21
+ line = me[1]
22
+ end
23
+
24
+ if me = %r{^\s*(.*)}.match(line)
25
+ line = me[1]
26
+ end
27
+
28
+ line
29
+ end.reject(&:blank?)
30
+
31
+ text_lines_without_comments.join("\n").split(%r{(?=\(function\(\))})
32
+ end
33
+
34
+ def snippet_and_beyond
35
+ gaq_split_at_snippet_beginning[1..-1]
36
+ end
37
+
38
+ def gaq_js_instructions
39
+ gaq_split_at_snippet_beginning.first.split(%r{(?<=;)\n}m)
40
+ end
41
+
42
+ def gaq_pushed_instructions
43
+ lines = %r{\A_gaq.push\((.*)\);\Z}m.match(gaq_js_instructions.second)[1]
44
+ lines.split(",\n").map do |instruction_line|
45
+ instruction_line.should start_with('[')
46
+ instruction_line.should end_with(']')
47
+
48
+ JSON.parse(instruction_line)
49
+ end
50
+ end
51
+
52
+ def track_event_from_before_filter(action)
53
+ be_instruction('_trackEvent').with_args("controller", "action", action)
54
+ end
55
+ end
56
+
57
+ RSpec.configure{ |c| c.include Helpers }
58
+
59
+ RSpec::Matchers.define :be_instruction do |instruction|
60
+ match do |actual|
61
+ (actual.first == instruction) &&
62
+ if defined?(@instruction_args)
63
+ (actual.drop(1) == @instruction_args)
64
+ else
65
+ true
66
+ end
67
+ end
68
+
69
+ chain :with_args do |*args|
70
+ @instruction_args = args
71
+ end
72
+
73
+ chain :without_args do
74
+ @instruction_args = []
75
+ end
76
+
77
+ failure_message_for_should do |actual|
78
+ message = "expected that #{actual} would be instruction #{instruction.inspect}"
79
+ if @instruction_args
80
+ if @instruction_args.empty?
81
+ message << "without args"
82
+ else
83
+ message << " with args #{@instruction_args}"
84
+ end
85
+ end
86
+ message
87
+ end
88
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+ require 'common_spec_methods'
3
+
4
+ describe "dynamic config interpretation", dynamic: true do
5
+ it "interprets web property id dynamically" do
6
+ visit '/snippet_presence?wip=UA-OVERRIDE-1'
7
+
8
+ first_instruction = gaq_pushed_instructions.first
9
+ first_instruction.should be_instruction("_setAccount", 'UA-OVERRIDE-1')
10
+ end
11
+
12
+ it "interprets anonymize_ip dynamically" do
13
+ visit '/snippet_presence?anonymize_ip=true'
14
+ gaq_pushed_instructions[1].should be_instruction('_gat._anonymizeIp')
15
+
16
+ visit '/snippet_presence?anonymize_ip=false'
17
+ gaq_pushed_instructions.each do |instruction|
18
+ instruction.should_not be_instruction('_gat._anonymizeIp')
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ require 'common_spec_methods'
3
+
4
+ describe "gaq next_request effect" do
5
+ it "renders events after redirect, but not after the request following" do
6
+ visit '/redirecting_action'
7
+
8
+ gaq_pushed_instructions.should have(4).items
9
+
10
+ first_instruction, second_instruction, third_instruction, fourth_instruction = gaq_pushed_instructions
11
+
12
+ first_instruction.should be_instruction("_setAccount")
13
+ second_instruction.should be_instruction("_trackPageview").without_args
14
+ third_instruction.should be_instruction('_trackEvent').with_args('from', 'redirecting', 'action')
15
+ fourth_instruction.should track_event_from_before_filter('target_action')
16
+
17
+ visit '/final_action'
18
+
19
+ gaq_pushed_instructions.should have(3).items
20
+
21
+ first_instruction, second_instruction, third_instruction = gaq_pushed_instructions
22
+
23
+ first_instruction.should be_instruction("_setAccount")
24
+ second_instruction.should be_instruction("_trackPageview").without_args
25
+ third_instruction.should track_event_from_before_filter('final_action')
26
+ end
27
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'common_spec_methods'
5
+
6
+ describe "gaq snippet presence" do
7
+ it "renders 'gaq' in the page" do
8
+ visit '/snippet_presence'
9
+ expect(page.body).to have_text("_gaq")
10
+ end
11
+
12
+ describe "conditional examples by rails environment" do
13
+ it "renders the configured basic web property id", :static do
14
+ visit '/snippet_presence'
15
+ expect(page.body).to have_text("UA-TESTSTAT-1")
16
+ end
17
+
18
+ it "renders the configured basic web property id", :dynamic do
19
+ visit '/snippet_presence'
20
+ expect(page.body).to have_text("UA-TESTDYNA-1")
21
+ end
22
+ end
23
+
24
+ describe "common spec methods" do
25
+ before { visit '/snippet_presence' }
26
+
27
+ it "renders a CDATA containing _gaq" do
28
+ gaq_cdata.should_not be_nil
29
+ end
30
+
31
+ it "starts by initializing _gaq array" do
32
+ gaq_js_instructions.first.should == "var _gaq = _gaq || [];"
33
+ end
34
+
35
+ it "continues with a _gaq.push line" do
36
+ gaq_js_instructions.second.should match(%r{\A_gaq.push\(.*\);\Z}m)
37
+ end
38
+
39
+ it "does not have more js lines before the snippet" do
40
+ gaq_js_instructions.should have(2).items
41
+ end
42
+
43
+ it "continues with the snippet, and that's the end" do
44
+ snippet_and_beyond.should have(1).item
45
+ snippet_and_beyond.first.should start_with('(function()')
46
+ snippet_and_beyond.first.should end_with('})();')
47
+ end
48
+
49
+ describe "pushed instructions" do
50
+ it "pushed the expected instructions, part 1" do
51
+ gaq_pushed_instructions.should have(3).items
52
+
53
+ first_instruction, second_instruction, third_instruction = gaq_pushed_instructions
54
+ first_instruction.should be_instruction("_setAccount")
55
+ second_instruction.should be_instruction("_trackPageview").without_args
56
+ third_instruction.should track_event_from_before_filter('snippet_presence')
57
+ end
58
+
59
+ it "pushed the expected instructions, part 2", :static do
60
+ gaq_pushed_instructions.first.should be_instruction("_setAccount").with_args('UA-TESTSTAT-1')
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,41 @@
1
+ # This file is copied to spec/ when you run 'rails generate rspec:install'
2
+ ENV["RAILS_ENV"] ||= 'test'
3
+ require File.expand_path("../../config/environment", __FILE__)
4
+ require 'rspec/rails'
5
+ require 'rspec/autorun'
6
+ require 'capybara/rails'
7
+
8
+ # Requires supporting ruby files with custom matchers and macros, etc,
9
+ # in spec/support/ and its subdirectories.
10
+ Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
11
+
12
+ RSpec.configure do |config|
13
+ # ## Mock Framework
14
+ #
15
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
16
+ #
17
+ # config.mock_with :mocha
18
+ # config.mock_with :flexmock
19
+ # config.mock_with :rr
20
+
21
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
22
+ # config.fixture_path = "#{::Rails.root}/spec/fixtures"
23
+
24
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
25
+ # examples within a transaction, remove the following line or assign false
26
+ # instead of true.
27
+ # config.use_transactional_fixtures = true
28
+
29
+ # If true, the base class of anonymous controllers will be inferred
30
+ # automatically. This will be the default behavior in future versions of
31
+ # rspec-rails.
32
+ config.infer_base_class_for_anonymous_controllers = false
33
+
34
+ # Run specs in random order to surface order dependencies. If you find an
35
+ # order dependency and want to debug it, you can fix the order by providing
36
+ # the seed, which is printed after each run.
37
+ # --seed 1234
38
+ config.order = "random"
39
+
40
+ config.treat_symbols_as_metadata_keys_with_true_values = true
41
+ end
@@ -0,0 +1,62 @@
1
+ require 'gaq/class_cache'
2
+
3
+ module Gaq
4
+ describe ClassCache do
5
+ let(:assertion_double) { double }
6
+
7
+ shared_context silence_double: true do
8
+ before do
9
+ assertion_double.as_null_object
10
+ end
11
+ end
12
+
13
+ before do
14
+ subject.building(:foo, String) do |cls|
15
+ assertion_double.build(:foo)
16
+ cls.class_eval do
17
+ def foo
18
+ "foo"
19
+ end
20
+ end
21
+ end
22
+
23
+ subject.building(:bar, Hash) do |cls|
24
+ assertion_double.build(:bar)
25
+ subject[:foo]
26
+ cls.class_eval do
27
+ def bar
28
+ "bar"
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ context silence_double: true do
35
+ it "builds a class as instructed" do
36
+ built = subject[:foo]
37
+ built.should be < String
38
+ built.new.foo.should be == "foo"
39
+ end
40
+
41
+ it "raises an exception on miss" do
42
+ expect {
43
+ subject[:baz]
44
+ }.to raise_exception ClassCache::Miss
45
+ end
46
+ end
47
+
48
+ it "only builds the class once" do
49
+ assertion_double.should_receive(:build).with(:foo).once
50
+
51
+ subject[:foo]
52
+ subject[:foo]
53
+ end
54
+
55
+ it "implicitly supports dependencies" do
56
+ assertion_double.should_receive(:build).with(:foo)
57
+
58
+ assertion_double.should_receive(:build).with(:bar)
59
+ subject[:bar]
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,267 @@
1
+ require 'gaq/command_language'
2
+
3
+ module Gaq
4
+ describe CommandLanguage do
5
+ let(:value_coercer) { double "value coercer" }
6
+
7
+ def null_coercing
8
+ value_coercer.stub(:call) { |type, value| value }
9
+ end
10
+
11
+ subject do
12
+ result = described_class.new
13
+ result.value_coercer = value_coercer
14
+ result
15
+ end
16
+
17
+ let(:descriptors) { {} }
18
+
19
+ before do
20
+ subject.knows_command(:foo) do |desc|
21
+ desc.signature = [String]
22
+ desc.name = "_myFooCommand"
23
+ descriptors[:foo] = desc
24
+ end if example.metadata[:foo_command]
25
+
26
+ subject.knows_command(:bar) do |desc|
27
+ desc.signature = [String, Integer]
28
+ desc.name = "_myBarCommand"
29
+ desc.sort_slot = 1
30
+ descriptors[:bar] = desc
31
+ end if example.metadata[:bar_command]
32
+
33
+ subject.knows_command(:baz) do |desc|
34
+ desc.signature = []
35
+ desc.name = "_myBazCommand"
36
+ desc.sort_slot = 0
37
+ descriptors[:baz] = desc
38
+ end if example.metadata[:baz_command]
39
+ end
40
+
41
+ RSpec::Matchers.define :be_identified_as do |identifier|
42
+ match do |command|
43
+ command.descriptor.identifier.equal? identifier
44
+ end
45
+ end
46
+
47
+ describe ".new_command" do
48
+ it "returns a properly identified and named command", foo_command: true do
49
+ null_coercing
50
+
51
+ command = subject.new_command(:foo, "string")
52
+
53
+ command.should be_identified_as(:foo)
54
+ command.name.should be == "_myFooCommand"
55
+ end
56
+
57
+ it "passes params through value coercer", foo_command: true do
58
+ value_coercer.should_receive(:call).with(String, "string").and_return "coerced string"
59
+
60
+ command = subject.new_command(:foo, "string")
61
+
62
+ command.params.should be == ["coerced string"]
63
+ end
64
+
65
+ it "passes only given params through coercer, even if less than signature length", bar_command: true do
66
+ value_coercer.should_receive(:call).with(String, "string").and_return "coerced string"
67
+
68
+ command = subject.new_command(:bar, "string")
69
+
70
+ command.params.should be == ["coerced string"]
71
+ end
72
+ end
73
+
74
+ shared_examples ".commands_to_flash_items behaves" do
75
+ let(:flash_data_item) do
76
+ flash_items = subject.commands_to_flash_items([command])
77
+ flash_items.should have(1).item
78
+ flash_items.first
79
+ end
80
+
81
+ context "with a command accepting two parameters", bar_command: true do
82
+ let(:command) do
83
+ command = CommandLanguage::Command.new
84
+ command.descriptor = descriptors[:bar]
85
+ command.name = "_myBarCommand"
86
+ command.params = []
87
+ command
88
+ end
89
+
90
+ it "adds params to data items" do
91
+ command.params << "first param" << "second param"
92
+
93
+ flash_data_item.should have(3).items
94
+ flash_data_item[1].should be == "first param"
95
+ flash_data_item[2].should be == "second param"
96
+ end
97
+
98
+ it "adds only as many params as signature length" do
99
+ command.params << "first param"
100
+
101
+ flash_data_item.should have(2).items
102
+ flash_data_item[1].should be == "first param"
103
+ end
104
+ end
105
+
106
+ context "with a command accepting one parameter", foo_command: true do
107
+ let(:command) do
108
+ command = CommandLanguage::Command.new
109
+ command.descriptor = descriptors[:foo]
110
+ command.name = "_myFooCommand"
111
+ command.params = ["param"]
112
+ command
113
+ end
114
+
115
+ it "sets the first flash item's first item to the command name (no target set)" do
116
+ null_coercing
117
+
118
+ flash_data_item.should have(2).items
119
+ flash_data_item.first.should be == "_myFooCommand"
120
+ end
121
+
122
+ it "sets the first flash item's first item to the command name (target set)" do
123
+ null_coercing
124
+
125
+ command.tracker_name = "tracker"
126
+
127
+ flash_data_item.should have(2).items
128
+ flash_data_item.first.should be == "tracker._myFooCommand"
129
+ end
130
+ end
131
+ end
132
+
133
+ describe ".commands_to_flash_items" do
134
+ let(:result) do
135
+ subject.commands_to_flash_items([command])
136
+ end
137
+
138
+ it_should_behave_like ".commands_to_flash_items behaves"
139
+ end
140
+
141
+ describe ".commands_to_segments_for_to_json" do
142
+ let(:result) do
143
+ subject.commands_to_segments_for_to_json([command])
144
+ end
145
+
146
+ it_should_behave_like ".commands_to_flash_items behaves"
147
+ end
148
+
149
+ describe ".sort_commands" do
150
+ def assert_order(commands)
151
+ commands[0].should be_identified_as(:baz)
152
+ commands[1].should be_identified_as(:bar)
153
+ commands[2].should be_identified_as(:foo)
154
+ end
155
+
156
+ it "sorts commands by sort_slot, missing sort_slot values last",
157
+ foo_command: true, bar_command: true, baz_command: true do
158
+ commands = [
159
+ subject.new_command(:foo),
160
+ subject.new_command(:bar),
161
+ subject.new_command(:baz)
162
+ ]
163
+
164
+ subject.sort_commands(commands)
165
+ assert_order(commands)
166
+
167
+ commands = [
168
+ subject.new_command(:bar),
169
+ subject.new_command(:foo),
170
+ subject.new_command(:baz)
171
+ ]
172
+
173
+ subject.sort_commands(commands)
174
+ assert_order(commands)
175
+ end
176
+ end
177
+
178
+ describe ".commands_from_flash_items", foo_command: true, bar_command: true do
179
+ it "correctly detects the command" do
180
+ flash_items = [
181
+ ["_myFooCommand"],
182
+ ["_myBarCommand"]
183
+ ]
184
+ commands = subject.commands_from_flash_items(flash_items)
185
+
186
+ commands.should have(2).items
187
+
188
+ command = commands.first
189
+ command.should be_identified_as(:foo)
190
+ command.name.should be == '_myFooCommand'
191
+
192
+ command = commands.last
193
+ command.should be_identified_as(:bar)
194
+ command.name.should be == '_myBarCommand'
195
+ end
196
+
197
+ it "sets command's params to remaining segments from flash item" do
198
+ flash_item = ["_myBarCommand", "first param", "second param"]
199
+
200
+ commands = subject.commands_from_flash_items([flash_item])
201
+
202
+ commands.should have(1).item
203
+ command = commands.first
204
+
205
+ command.params.should be == ["first param", "second param"]
206
+ end
207
+
208
+ it "sets tracker name to nil when no explicit tracker given" do
209
+ flash_item = ["_myFooCommand"]
210
+ commands = subject.commands_from_flash_items([flash_item])
211
+
212
+ commands.should have(1).item
213
+ command = commands.first
214
+
215
+ command.tracker_name.should be_nil
216
+ end
217
+
218
+ it "correctly sets present tracker name" do
219
+ flash_item = ["my_tracker._myFooCommand"]
220
+ commands = subject.commands_from_flash_items([flash_item])
221
+
222
+ commands.should have(1).item
223
+ command = commands.first
224
+
225
+ command.tracker_name.should be == "my_tracker"
226
+ end
227
+ end
228
+
229
+ describe ".coerce_value" do
230
+ describe "type :Boolean" do
231
+ it "coerces boolish values properly" do
232
+ described_class.coerce_value(:Boolean, true).should be true
233
+ described_class.coerce_value(:Boolean, false).should be false
234
+
235
+ described_class.coerce_value(:Boolean, 1).should be true
236
+ described_class.coerce_value(:Boolean, nil).should be false
237
+ end
238
+ end
239
+
240
+ describe "type :String" do
241
+ it "coerces values like String()" do
242
+ described_class.coerce_value(:String, "str").should be == "str"
243
+ described_class.coerce_value(:String, 1).should be == "1"
244
+
245
+ expect {
246
+ described_class.coerce_value(:String, BasicObject.new)
247
+ }.to raise_exception
248
+ end
249
+ end
250
+
251
+ describe "type :Int" do
252
+ it "coerces values like Integer()" do
253
+ described_class.coerce_value(:Int, 1).should be 1
254
+ described_class.coerce_value(:Int, "5").should be 5
255
+
256
+ expect {
257
+ described_class.coerce_value(:Int, "_")
258
+ }.to raise_exception
259
+
260
+ expect {
261
+ described_class.coerce_value(:Int, "3.14")
262
+ }.to raise_exception
263
+ end
264
+ end
265
+ end
266
+ end
267
+ end