detour 0.0.1 → 0.0.2

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 (147) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -1
  3. data/.travis.yml +6 -2
  4. data/Gemfile +5 -0
  5. data/README.md +41 -132
  6. data/Rake.md +108 -0
  7. data/Rakefile +21 -1
  8. data/app/assets/fonts/glyphicons-halflings-regular.eot +0 -0
  9. data/app/assets/fonts/glyphicons-halflings-regular.svg +229 -0
  10. data/app/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  11. data/app/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  12. data/app/assets/images/detour/.gitkeep +0 -0
  13. data/app/assets/javascripts/detour/application.js +16 -0
  14. data/app/assets/javascripts/detour/bootstrap.js +2006 -0
  15. data/app/assets/javascripts/detour/delete_feature.js +13 -0
  16. data/app/assets/javascripts/detour/delete_flag.js +13 -0
  17. data/app/assets/javascripts/detour/modals.js +3 -0
  18. data/app/assets/javascripts/detour/tooltips.js +3 -0
  19. data/app/assets/stylesheets/detour/application.css +14 -0
  20. data/app/assets/stylesheets/detour/bootstrap.css +7112 -0
  21. data/app/assets/stylesheets/detour/main.css +49 -0
  22. data/app/controllers/detour/application_controller.rb +12 -0
  23. data/app/controllers/detour/features_controller.rb +19 -0
  24. data/app/controllers/detour/flaggable_flags_controller.rb +90 -0
  25. data/app/controllers/detour/flags_controller.rb +18 -0
  26. data/app/helpers/detour/application_helper.rb +32 -0
  27. data/app/helpers/detour/flaggable_flags_helper.rb +5 -0
  28. data/app/helpers/detour/flags_helper.rb +7 -0
  29. data/app/models/detour/concerns/countable_flag.rb +19 -0
  30. data/app/models/detour/concerns/flag_actions.rb +141 -0
  31. data/app/models/detour/concerns/matchers.rb +73 -0
  32. data/app/models/detour/feature.rb +81 -0
  33. data/{lib → app/models}/detour/flag.rb +8 -2
  34. data/app/models/detour/flag_in_flag.rb +12 -0
  35. data/app/models/detour/group_flag.rb +13 -0
  36. data/{lib → app/models}/detour/opt_out_flag.rb +4 -2
  37. data/app/models/detour/percentage_flag.rb +9 -0
  38. data/app/views/detour/application/index.html.erb +0 -0
  39. data/app/views/detour/features/_errors.html.erb +11 -0
  40. data/app/views/detour/features/_success.html.erb +1 -0
  41. data/app/views/detour/features/error.js.erb +5 -0
  42. data/app/views/detour/features/success.js.erb +1 -0
  43. data/app/views/detour/flaggable_flags/_errors.html.erb +11 -0
  44. data/app/views/detour/flaggable_flags/_flaggable_flag.html.erb +11 -0
  45. data/app/views/detour/flaggable_flags/error.js.erb +5 -0
  46. data/app/views/detour/flaggable_flags/index.html.erb +34 -0
  47. data/app/views/detour/flaggable_flags/success.js.erb +1 -0
  48. data/app/views/detour/flags/_feature_form.html.erb +38 -0
  49. data/app/views/detour/flags/index.html.erb +76 -0
  50. data/app/views/detour/shared/_nav.html.erb +28 -0
  51. data/app/views/detour/shared/_spacer_cells.html.erb +3 -0
  52. data/app/views/layouts/detour/application.html.erb +29 -0
  53. data/config/routes.rb +16 -0
  54. data/detour.gemspec +15 -14
  55. data/lib/detour/acts_as_flaggable.rb +42 -3
  56. data/lib/detour/configuration.rb +35 -0
  57. data/lib/detour/engine.rb +5 -0
  58. data/lib/detour/flag_form.rb +87 -0
  59. data/lib/detour/version.rb +1 -1
  60. data/lib/detour.rb +10 -14
  61. data/lib/generators/templates/migration.rb +2 -0
  62. data/lib/tasks/detour.rake +16 -16
  63. data/script/rails +8 -0
  64. data/spec/controllers/detour/application_controller_spec.rb +15 -0
  65. data/spec/controllers/detour/features_controller_spec.rb +51 -0
  66. data/spec/controllers/detour/flaggable_flags_controller_spec.rb +100 -0
  67. data/spec/controllers/detour/flags_controller_spec.rb +77 -0
  68. data/spec/dummy/README.rdoc +261 -0
  69. data/spec/dummy/Rakefile +7 -0
  70. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  71. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  72. data/spec/dummy/app/controllers/application_controller.rb +7 -0
  73. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  74. data/spec/dummy/app/mailers/.gitkeep +0 -0
  75. data/spec/dummy/app/models/.gitkeep +0 -0
  76. data/spec/dummy/app/models/user.rb +5 -0
  77. data/spec/dummy/app/models/widget.rb +5 -0
  78. data/spec/dummy/app/views/application/index.html.erb +22 -0
  79. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  80. data/spec/dummy/config/application.rb +65 -0
  81. data/spec/dummy/config/boot.rb +10 -0
  82. data/spec/dummy/config/database.yml +19 -0
  83. data/spec/dummy/config/environment.rb +5 -0
  84. data/spec/dummy/config/environments/development.rb +37 -0
  85. data/spec/dummy/config/environments/production.rb +67 -0
  86. data/spec/dummy/config/environments/test.rb +37 -0
  87. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  88. data/spec/dummy/config/initializers/detour.rb +36 -0
  89. data/spec/dummy/config/initializers/inflections.rb +15 -0
  90. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  91. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  92. data/spec/dummy/config/initializers/session_store.rb +8 -0
  93. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  94. data/spec/dummy/config/locales/en.yml +5 -0
  95. data/spec/dummy/config/routes.rb +4 -0
  96. data/spec/dummy/config.ru +4 -0
  97. data/spec/dummy/db/migrate/20131218015844_create_users.rb +10 -0
  98. data/spec/dummy/db/migrate/20131218023124_create_widgets.rb +9 -0
  99. data/spec/dummy/db/migrate/20131218055352_add_user_id_to_widgets.rb +6 -0
  100. data/spec/dummy/db/migrate/20131221052201_setup_detour.rb +32 -0
  101. data/spec/dummy/db/schema.rb +59 -0
  102. data/spec/dummy/db/seeds.rb +10 -0
  103. data/spec/dummy/lib/assets/.gitkeep +0 -0
  104. data/spec/dummy/log/.gitkeep +0 -0
  105. data/spec/dummy/public/404.html +26 -0
  106. data/spec/dummy/public/422.html +26 -0
  107. data/spec/dummy/public/500.html +25 -0
  108. data/spec/dummy/public/favicon.ico +0 -0
  109. data/spec/dummy/script/rails +6 -0
  110. data/spec/factories/feature.rb +5 -0
  111. data/spec/factories/flag_in_flag.rb +6 -0
  112. data/spec/factories/group_flag.rb +7 -0
  113. data/spec/factories/opt_out_flag.rb +6 -0
  114. data/spec/factories/percentage_flag.rb +7 -0
  115. data/spec/factories/user.rb +6 -0
  116. data/spec/factories/widget.rb +5 -0
  117. data/spec/features/features_spec.rb +70 -0
  118. data/spec/features/flag_in_flags_spec.rb +118 -0
  119. data/spec/features/group_flags_spec.rb +49 -0
  120. data/spec/features/home_page_spec.rb +11 -0
  121. data/spec/features/opt_out_flags_spec.rb +105 -0
  122. data/spec/features/percentage_flags_spec.rb +63 -0
  123. data/spec/integration/group_rollout_spec.rb +1 -1
  124. data/spec/lib/detour/acts_as_flaggable_spec.rb +45 -0
  125. data/spec/lib/detour/configuration_spec.rb +23 -0
  126. data/spec/lib/detour/flag_form_spec.rb +84 -0
  127. data/spec/lib/{active_record/rollout → detour}/flaggable_spec.rb +19 -19
  128. data/spec/lib/tasks/{detour_rake_spec.rb → detour_spec.rb} +54 -54
  129. data/spec/{lib/active_record/rollout → models/detour}/feature_spec.rb +93 -67
  130. data/spec/models/detour/flag_in_flag_spec.rb +38 -0
  131. data/spec/{lib/active_record/rollout → models/detour}/flag_spec.rb +1 -1
  132. data/spec/models/detour/opt_out_flag_spec.rb +38 -0
  133. data/spec/{lib/active_record/rollout → models/detour}/percentage_flag_spec.rb +1 -1
  134. data/spec/spec_helper.rb +41 -21
  135. data/spec/support/shared_contexts/rake.rb +4 -14
  136. metadata +278 -95
  137. data/lib/detour/feature.rb +0 -312
  138. data/lib/detour/flaggable_flag.rb +0 -10
  139. data/lib/detour/group_flag.rb +0 -8
  140. data/lib/detour/percentage_flag.rb +0 -11
  141. data/spec/lib/active_record/rollout/acts_as_flaggable_spec.rb +0 -31
  142. data/spec/lib/active_record/rollout/flaggable_flag_spec.rb +0 -9
  143. data/spec/lib/active_record/rollout/opt_out_flag_spec.rb +0 -9
  144. data/spec/support/schema.rb +0 -13
  145. /data/lib/generators/{active_record_rollout_generator.rb → detour_generator.rb} +0 -0
  146. /data/lib/generators/templates/{active_record_rollout.rb → detour.rb} +0 -0
  147. /data/spec/{lib/active_record/rollout → models/detour}/group_flag_spec.rb +0 -0
@@ -12,151 +12,151 @@ end
12
12
  describe "detour:destroy" do
13
13
  include_context "rake"
14
14
 
15
- let(:feature) { Detour::Feature.create(name: "foo") }
15
+ let(:feature) { create :feature }
16
16
 
17
17
  it "destroys the given feature" do
18
18
  Detour::Feature.should_receive(:find_by_name!).with(feature.name).and_return(feature)
19
19
  feature.should_receive(:destroy)
20
- subject.invoke("foo")
20
+ subject.invoke(feature.name)
21
21
  end
22
22
  end
23
23
 
24
24
  describe "detour:activate" do
25
25
  include_context "rake"
26
26
 
27
- let(:user) { User.create(name: "foo") }
28
- let!(:feature) { Detour::Feature.create(name: "foo") }
27
+ let(:user) { create :user }
28
+ let(:feature) { create :feature }
29
29
 
30
30
  it "activates the feature for the record" do
31
- Detour::Feature.should_receive(:add_record_to_feature).with(user, "foo")
32
- subject.invoke("foo", "User", user.id.to_s)
31
+ Detour::Feature.should_receive(:add_record_to_feature).with(user, feature.name)
32
+ subject.invoke(feature.name, user.class.to_s, user.id.to_s)
33
33
  end
34
34
 
35
35
  it "does not require a class if defined_flaggable_class is set" do
36
- Detour::Feature.should_receive(:add_record_to_feature).with(user, "foo")
37
- Detour::Feature.instance_variable_set "@default_flaggable_class_name", "User"
38
- expect { subject.invoke("foo", user.id.to_s) }.to_not raise_error
36
+ Detour::Feature.should_receive(:add_record_to_feature).with(user, feature.name)
37
+ Detour.config.default_flaggable_class_name = user.class.to_s
38
+ expect { subject.invoke(feature.name, user.id.to_s) }.to_not raise_error
39
39
  end
40
40
  end
41
41
 
42
42
  describe "detour:deactivate" do
43
43
  include_context "rake"
44
44
 
45
- let(:user) { User.create(name: "foo") }
46
- let!(:feature) { Detour::Feature.create(name: "foo") }
45
+ let(:user) { create :user }
46
+ let(:feature) { create :feature }
47
47
 
48
48
  it "deactivates the feature for the record" do
49
- Detour::Feature.should_receive(:remove_record_from_feature).with(user, "foo")
50
- subject.invoke("foo", "User", user.id.to_s)
49
+ Detour::Feature.should_receive(:remove_record_from_feature).with(user, feature.name)
50
+ subject.invoke(feature.name, user.class.to_s, user.id.to_s)
51
51
  end
52
52
 
53
53
  it "does not require a class if defined_flaggable_class is set" do
54
- Detour::Feature.should_receive(:remove_record_from_feature).with(user, "foo")
55
- Detour::Feature.instance_variable_set "@default_flaggable_class_name", "User"
56
- expect { subject.invoke("foo", user.id.to_s) }.to_not raise_error
54
+ Detour::Feature.should_receive(:remove_record_from_feature).with(user, feature.name)
55
+ Detour.config.default_flaggable_class_name = user.class.to_s
56
+ expect { subject.invoke(feature.name, user.id.to_s) }.to_not raise_error
57
57
  end
58
58
  end
59
59
 
60
60
  describe "detour:opt_out" do
61
61
  include_context "rake"
62
62
 
63
- let(:user) { User.create(name: "foo") }
64
- let!(:feature) { Detour::Feature.create(name: "foo") }
63
+ let(:user) { create :user }
64
+ let(:feature) { create :feature }
65
65
 
66
66
  it "deactivates the feature for the record" do
67
- Detour::Feature.should_receive(:opt_record_out_of_feature).with(user, "foo")
68
- subject.invoke("foo", "User", user.id.to_s)
67
+ Detour::Feature.should_receive(:opt_record_out_of_feature).with(user, feature.name)
68
+ subject.invoke(feature.name, user.class.to_s, user.id.to_s)
69
69
  end
70
70
 
71
71
  it "does not require a class if defined_flaggable_class is set" do
72
- Detour::Feature.should_receive(:opt_record_out_of_feature).with(user, "foo")
73
- Detour::Feature.instance_variable_set "@default_flaggable_class_name", "User"
74
- expect { subject.invoke("foo", user.id.to_s) }.to_not raise_error
72
+ Detour::Feature.should_receive(:opt_record_out_of_feature).with(user, feature.name)
73
+ Detour.config.default_flaggable_class_name = user.class.to_s
74
+ expect { subject.invoke(feature.name, user.id.to_s) }.to_not raise_error
75
75
  end
76
76
  end
77
77
 
78
78
  describe "detour:un_opt_out" do
79
79
  include_context "rake"
80
80
 
81
- let(:user) { User.create(name: "foo") }
82
- let!(:feature) { Detour::Feature.create(name: "foo") }
81
+ let(:user) { create :user }
82
+ let(:feature) { create :feature }
83
83
 
84
84
  it "deactivates the feature for the record" do
85
- Detour::Feature.should_receive(:un_opt_record_out_of_feature).with(user, "foo")
86
- subject.invoke("foo", "User", user.id.to_s)
85
+ Detour::Feature.should_receive(:un_opt_record_out_of_feature).with(user, feature.name)
86
+ subject.invoke(feature.name, user.class.to_s, user.id.to_s)
87
87
  end
88
88
 
89
89
  it "does not require a class if defined_flaggable_class is set" do
90
- Detour::Feature.should_receive(:un_opt_record_out_of_feature).with(user, "foo")
91
- Detour::Feature.instance_variable_set "@default_flaggable_class_name", "User"
92
- expect { subject.invoke("foo", user.id.to_s) }.to_not raise_error
90
+ Detour::Feature.should_receive(:un_opt_record_out_of_feature).with(user, feature.name)
91
+ Detour.config.default_flaggable_class_name = user.class.to_s
92
+ expect { subject.invoke(feature.name, user.id.to_s) }.to_not raise_error
93
93
  end
94
94
  end
95
95
 
96
96
  describe "detour:activate_group" do
97
97
  include_context "rake"
98
98
 
99
- let!(:feature) { Detour::Feature.create(name: "foo") }
99
+ let(:feature) { create :feature }
100
100
 
101
101
  it "activates the feature for the group" do
102
- Detour::Feature.should_receive(:add_group_to_feature).with("User", "admins", "foo")
103
- subject.invoke("foo", "User", "admins")
102
+ Detour::Feature.should_receive(:add_group_to_feature).with("User", "admins", feature.name)
103
+ subject.invoke(feature.name, "User", "admins")
104
104
  end
105
105
 
106
106
  it "does not require a class if defined_flaggable_class is set" do
107
- Detour::Feature.should_receive(:add_group_to_feature).with("User", "admins", "foo")
108
- Detour::Feature.instance_variable_set "@default_flaggable_class_name", "User"
109
- expect { subject.invoke("foo", "admins") }.to_not raise_error
107
+ Detour::Feature.should_receive(:add_group_to_feature).with("User", "admins", feature.name)
108
+ Detour.config.default_flaggable_class_name = "User"
109
+ expect { subject.invoke(feature.name, "admins") }.to_not raise_error
110
110
  end
111
111
  end
112
112
 
113
113
  describe "detour:deactivate_group" do
114
114
  include_context "rake"
115
115
 
116
- let!(:feature) { Detour::Feature.create(name: "foo") }
116
+ let(:feature) { create :feature }
117
117
 
118
118
  it "deactivates the feature for the group" do
119
- Detour::Feature.should_receive(:remove_group_from_feature).with("User", "admins", "foo")
120
- subject.invoke("foo", "User", "admins")
119
+ Detour::Feature.should_receive(:remove_group_from_feature).with("User", "admins", feature.name)
120
+ subject.invoke(feature.name, "User", "admins")
121
121
  end
122
122
 
123
123
  it "does not require a class if defined_flaggable_class is set" do
124
- Detour::Feature.should_receive(:remove_group_from_feature).with("User", "admins", "foo")
125
- Detour::Feature.instance_variable_set "@default_flaggable_class_name", "User"
126
- expect { subject.invoke("foo", "admins") }.to_not raise_error
124
+ Detour::Feature.should_receive(:remove_group_from_feature).with("User", "admins", feature.name)
125
+ Detour.config.default_flaggable_class_name = "User"
126
+ expect { subject.invoke(feature.name, "admins") }.to_not raise_error
127
127
  end
128
128
  end
129
129
 
130
130
  describe "detour:activate_percentage" do
131
131
  include_context "rake"
132
132
 
133
- let!(:feature) { Detour::Feature.create(name: "foo") }
133
+ let(:feature) { create :feature }
134
134
 
135
135
  it "activates the feature for the percentage" do
136
- Detour::Feature.should_receive(:add_percentage_to_feature).with("User", 50, "foo")
137
- subject.invoke("foo", "User", "50")
136
+ Detour::Feature.should_receive(:add_percentage_to_feature).with("User", 50, feature.name)
137
+ subject.invoke(feature.name, "User", "50")
138
138
  end
139
139
 
140
140
  it "does not require a class if defined_flaggable_class is set" do
141
- Detour::Feature.should_receive(:add_percentage_to_feature).with("User", 50, "foo")
142
- Detour::Feature.instance_variable_set "@default_flaggable_class_name", "User"
143
- expect { subject.invoke("foo", "50") }.to_not raise_error
141
+ Detour::Feature.should_receive(:add_percentage_to_feature).with("User", 50, feature.name)
142
+ Detour.config.default_flaggable_class_name = "User"
143
+ expect { subject.invoke(feature.name, "50") }.to_not raise_error
144
144
  end
145
145
  end
146
146
 
147
147
  describe "detour:deactivate_percentage" do
148
148
  include_context "rake"
149
149
 
150
- let!(:feature) { Detour::Feature.create(name: "foo") }
150
+ let(:feature) { create :feature }
151
151
 
152
152
  it "deactivates the feature for the percentage" do
153
- Detour::Feature.should_receive(:remove_percentage_from_feature).with("User", "foo")
154
- subject.invoke("foo", "User")
153
+ Detour::Feature.should_receive(:remove_percentage_from_feature).with("User", feature.name)
154
+ subject.invoke(feature.name, "User")
155
155
  end
156
156
 
157
157
  it "does not require a class if defined_flaggable_class is set" do
158
- Detour::Feature.should_receive(:remove_percentage_from_feature).with("User", "foo")
159
- Detour::Feature.instance_variable_set "@default_flaggable_class_name", "User"
160
- expect { subject.invoke("foo") }.to_not raise_error
158
+ Detour::Feature.should_receive(:remove_percentage_from_feature).with("User", feature.name)
159
+ Detour.config.default_flaggable_class_name = "User"
160
+ expect { subject.invoke(feature.name) }.to_not raise_error
161
161
  end
162
162
  end
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
  require "fakefs/spec_helpers"
3
3
 
4
4
  describe Detour::Feature do
5
- it { should have_many(:flaggable_flags) }
5
+ it { should have_many(:flag_in_flags) }
6
6
  it { should have_many(:group_flags) }
7
7
  it { should have_many(:percentage_flags) }
8
8
  it { should have_many(:opt_out_flags) }
@@ -11,13 +11,13 @@ describe Detour::Feature do
11
11
  it { should validate_uniqueness_of :name }
12
12
  it { should allow_mass_assignment_of :name }
13
13
 
14
- describe ".all_with_lines" do
14
+ describe ".with_lines" do
15
15
  include FakeFS::SpecHelpers
16
16
 
17
- let!(:feature) { Detour::Feature.create!(name: "foo") }
17
+ let(:feature) { create :feature, name: "foo" }
18
18
 
19
19
  before do
20
- Detour::Feature.grep_dirs = ["/foo/**/*.rb"]
20
+ Detour.config.grep_dirs = ["/foo/**/*.rb"]
21
21
 
22
22
  FileUtils.mkdir("/foo")
23
23
 
@@ -45,30 +45,22 @@ describe Detour::Feature do
45
45
  end
46
46
 
47
47
  it "fetches lines for persisted features" do
48
- persisted_feature = Detour::Feature.all_with_lines.detect { |f| f.name == feature.name }
48
+ persisted_feature = Detour::Feature.with_lines.detect { |f| f.name == feature.name }
49
49
  persisted_feature.lines.should eq %w[/foo/bar.rb#L1 /foo/bar.rb#L7 /foo/baz.rb#L1]
50
50
  end
51
51
 
52
52
  it "fetches lines for un-persisted features" do
53
- unpersisted_feature = Detour::Feature.all_with_lines.detect { |f| f.name == "bar" }
53
+ unpersisted_feature = Detour::Feature.with_lines.detect { |f| f.name == "bar" }
54
54
  unpersisted_feature.lines.should eq %w[/foo/bar.rb#L4 /foo/baz.rb#L1 /foo/baz.rb#L3]
55
55
  end
56
56
  end
57
57
 
58
- describe ".define_{klass}_group" do
59
- let(:block) { Proc.new {} }
60
- it "defines a group for the given class" do
61
- Detour::Feature.should_receive(:define_group_for_class).with("User", :id_is_1)
62
- Detour::Feature.define_user_group :id_is_1, block
63
- end
64
- end
65
-
66
58
  describe ".add_record_to_feature" do
67
- let(:user) { User.create }
68
- let!(:feature) { Detour::Feature.create!(name: "foo") }
59
+ let(:user) { create :user }
60
+ let(:feature) { create :feature }
69
61
 
70
62
  before do
71
- Detour::Feature.add_record_to_feature user, :foo
63
+ Detour::Feature.add_record_to_feature user, feature.name
72
64
  end
73
65
 
74
66
  it "creates a flag for the given instance and feature" do
@@ -77,12 +69,12 @@ describe Detour::Feature do
77
69
  end
78
70
 
79
71
  describe ".remove_record_from_feature" do
80
- let(:user) { User.create }
81
- let!(:feature) { Detour::Feature.create!(name: "foo") }
72
+ let(:user) { create :user }
73
+ let(:feature) { create :feature }
82
74
 
83
75
  before do
84
- Detour::Feature.add_record_to_feature user, :foo
85
- Detour::Feature.remove_record_from_feature user, :foo
76
+ Detour::Feature.add_record_to_feature user, feature.name
77
+ Detour::Feature.remove_record_from_feature user, feature.name
86
78
  end
87
79
 
88
80
  it "creates a flag for the given instance and feature" do
@@ -91,41 +83,41 @@ describe Detour::Feature do
91
83
  end
92
84
 
93
85
  describe ".opt_record_out_of_feature" do
94
- let(:user) { User.create }
95
- let!(:feature) { Detour::Feature.create!(name: "foo") }
86
+ let(:user) { create :user }
87
+ let(:feature) { create :feature }
96
88
 
97
89
  before do
98
- Detour::Feature.add_percentage_to_feature "User", 100, "foo"
99
- Detour::Feature.opt_record_out_of_feature user, "foo"
90
+ Detour::Feature.add_percentage_to_feature user.class.to_s, 100, feature.name
91
+ Detour::Feature.opt_record_out_of_feature user, feature.name
100
92
  end
101
93
 
102
94
  it "opts the record out of the feature" do
103
- user.has_feature?("foo").should be_false
95
+ user.has_feature?(feature.name).should be_false
104
96
  end
105
97
  end
106
98
 
107
99
  describe ".un_opt_record_out_of_feature" do
108
- let(:user) { User.create }
109
- let!(:feature) { Detour::Feature.create!(name: "foo") }
100
+ let(:user) { create :user }
101
+ let(:feature) { create :feature }
110
102
 
111
103
  before do
112
- Detour::Feature.add_percentage_to_feature "User", 100, "foo"
113
- Detour::Feature.opt_record_out_of_feature user, "foo"
114
- Detour::Feature.un_opt_record_out_of_feature user, "foo"
104
+ Detour::Feature.add_percentage_to_feature user.class.to_s, 100, feature.name
105
+ Detour::Feature.opt_record_out_of_feature user, feature.name
106
+ Detour::Feature.un_opt_record_out_of_feature user, feature.name
115
107
  end
116
108
 
117
109
  it "opts the record out of the feature" do
118
- user.has_feature?("foo").should be_true
110
+ user.has_feature?(feature.name).should be_true
119
111
  end
120
112
  end
121
113
 
122
114
  describe ".add_group_to_feature" do
123
- let!(:feature) { Detour::Feature.create!(name: "foo") }
115
+ let(:feature) { create :feature }
124
116
 
125
117
  before do
126
- Detour::Feature.define_user_group :bar do
118
+ Detour.config.define_user_group :bar do
127
119
  end
128
- Detour::Feature.add_group_to_feature "User", :bar, "foo"
120
+ Detour::Feature.add_group_to_feature "User", :bar, feature.name
129
121
  end
130
122
 
131
123
  it "creates a flag for the given group and feature" do
@@ -134,13 +126,13 @@ describe Detour::Feature do
134
126
  end
135
127
 
136
128
  describe ".remove_group_from_feature" do
137
- let!(:feature) { Detour::Feature.create!(name: "foo") }
129
+ let(:feature) { create :feature }
138
130
 
139
131
  before do
140
- Detour::Feature.define_user_group :bar do
132
+ Detour.config.define_user_group :bar do
141
133
  end
142
- Detour::Feature.add_group_to_feature "User", :bar, "foo"
143
- Detour::Feature.remove_group_from_feature "User", :bar, "foo"
134
+ Detour::Feature.add_group_to_feature "User", :bar, feature.name
135
+ Detour::Feature.remove_group_from_feature "User", :bar, feature.name
144
136
  end
145
137
 
146
138
  it "destroys flags for the given group and feature" do
@@ -149,10 +141,10 @@ describe Detour::Feature do
149
141
  end
150
142
 
151
143
  describe ".add_percentage_to_feature" do
152
- let!(:feature) { Detour::Feature.create!(name: "foo") }
144
+ let(:feature) { create :feature }
153
145
 
154
146
  before do
155
- Detour::Feature.add_percentage_to_feature "User", 50, "foo"
147
+ Detour::Feature.add_percentage_to_feature "User", 50, feature.name
156
148
  end
157
149
 
158
150
  it "creates a flag for the given percentage and feature" do
@@ -161,11 +153,11 @@ describe Detour::Feature do
161
153
  end
162
154
 
163
155
  describe ".remove_percentage_from_feature" do
164
- let!(:feature) { Detour::Feature.create!(name: "foo") }
156
+ let(:feature) { create :feature }
165
157
 
166
158
  before do
167
- Detour::Feature.add_percentage_to_feature "User", 50, "foo"
168
- Detour::Feature.remove_percentage_from_feature "User", "foo"
159
+ Detour::Feature.add_percentage_to_feature "User", 50, feature.name
160
+ Detour::Feature.remove_percentage_from_feature "User", feature.name
169
161
  end
170
162
 
171
163
  it "creates a flag for the given percentage and feature" do
@@ -173,20 +165,17 @@ describe Detour::Feature do
173
165
  end
174
166
  end
175
167
 
176
- describe ".define_group_for_class" do
177
- let(:block) { Proc.new {} }
178
- before do
179
- Detour::Feature.send :define_group_for_class, "User", "user_id_1", &block
180
- end
168
+ describe "#to_s" do
169
+ let(:feature) { create :feature }
181
170
 
182
- it "defines a group for the given class" do
183
- Detour::Feature.defined_groups["User"].should eq({ "user_id_1" => block })
171
+ it "returns the name of the feature" do
172
+ feature.to_s.should eq feature.name
184
173
  end
185
174
  end
186
175
 
187
176
  describe "#match?" do
188
- let(:user) { User.create }
189
- let(:feature) { Detour::Feature.create(name: "foo") }
177
+ let(:user) { create :user }
178
+ let(:feature) { create :feature }
190
179
 
191
180
  it "checks if the user is flagged individually" do
192
181
  feature.should_receive(:match_id?).with(user)
@@ -204,13 +193,50 @@ describe Detour::Feature do
204
193
  end
205
194
  end
206
195
 
196
+ describe "#flag_in_count_for" do
197
+ context "when a value does not exist" do
198
+ let(:feature) { create :feature }
199
+
200
+ it "returns 0" do
201
+ feature.flag_in_count_for("users").should eq 0
202
+ end
203
+ end
204
+
205
+ context "when a value exists" do
206
+ let(:feature) { create :feature, flag_in_counts: { "users" => 10 } }
207
+
208
+ it "returns the value" do
209
+ feature.flag_in_count_for("users").should eq 10
210
+ end
211
+ end
212
+ end
213
+
214
+ describe "#opt_out_count_for" do
215
+ context "when a value does not exist" do
216
+ let(:feature) { create :feature }
217
+
218
+ it "returns 0" do
219
+ feature.opt_out_count_for("users").should eq 0
220
+ end
221
+ end
222
+
223
+ context "when a value exists" do
224
+ let(:feature) { create :feature, opt_out_counts: { "users" => 10 } }
225
+
226
+ it "returns the value" do
227
+ feature.opt_out_count_for("users").should eq 10
228
+ end
229
+ end
230
+ end
231
+
232
+
207
233
  describe "#match_id?" do
208
- let(:user) { User.create }
209
- let(:user2) { User.create }
210
- let!(:feature) { Detour::Feature.create!(name: "foo") }
234
+ let(:user) { create :user }
235
+ let(:user2) { create :user }
236
+ let(:feature) { create :feature }
211
237
 
212
238
  before do
213
- Detour::Feature.add_record_to_feature user, :foo
239
+ Detour::Feature.add_record_to_feature user, feature.name
214
240
  end
215
241
 
216
242
  context "when the feature exists for the instance" do
@@ -227,9 +253,9 @@ describe Detour::Feature do
227
253
  end
228
254
 
229
255
  describe "#match_percentage?" do
230
- let(:user) { User.create }
231
- let(:feature) { Detour::Feature.create!(name: "foo") }
232
- let!(:flag) { feature.percentage_flags.create(flaggable_type: "User", percentage: 50) }
256
+ let(:user) { create :user }
257
+ let(:feature) { create :feature }
258
+ let!(:flag) { create :percentage_flag, feature: feature, flaggable_type: user.class.to_s, percentage: 50 }
233
259
 
234
260
  context "when the user's ID matches `id % 10 < percentage / 10" do
235
261
  it "returns true" do
@@ -247,14 +273,14 @@ describe Detour::Feature do
247
273
  end
248
274
 
249
275
  describe "#match_groups?" do
250
- let!(:user) { User.create(name: "foo") }
251
- let!(:user2) { User.create(name: "bar") }
252
- let!(:organization) { Organization.create(name: "foo") }
253
- let(:feature) { Detour::Feature.create!(name: "baz") }
254
- let!(:flag) { feature.group_flags.create(flaggable_type: "User", group_name: "foo_users") }
276
+ let(:user) { create :user, name: "foo" }
277
+ let(:user2) { create :user }
278
+ let(:widget) { create :widget }
279
+ let(:feature) { create :feature }
280
+ let!(:flag) { create :group_flag, feature: feature, flaggable_type: user.class.to_s, group_name: "foo_users" }
255
281
 
256
282
  before do
257
- Detour::Feature.define_user_group "foo_users" do |user|
283
+ Detour.config.define_user_group "foo_users" do |user|
258
284
  user.name == "foo"
259
285
  end
260
286
  end
@@ -273,7 +299,7 @@ describe Detour::Feature do
273
299
 
274
300
  context "when the instance is not of the type of the block" do
275
301
  it "returns false" do
276
- feature.match_groups?(organization).should be_false
302
+ feature.match_groups?(widget).should be_false
277
303
  end
278
304
  end
279
305
  end
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+
3
+ describe Detour::FlagInFlag do
4
+ it { should be_a Detour::Flag }
5
+ it { should belong_to :flaggable }
6
+ it { should validate_presence_of :flaggable }
7
+ it { should allow_mass_assignment_of :flaggable }
8
+
9
+ it "validates uniquness of feature_id on flaggable" do
10
+ user = create :user
11
+ flag = create :flag_in_flag, flaggable: user
12
+ flag2 = build :flag_in_flag, flaggable: user, feature: flag.feature
13
+
14
+ flag2.should_not be_valid
15
+ flag2.errors.full_messages.should eq ["Feature has already been taken"]
16
+ end
17
+
18
+ describe "when creating" do
19
+ let(:flag) { create :flag_in_flag }
20
+
21
+ it "increments its feature's flag_in_count" do
22
+ flag.reload.feature.flag_in_count_for(flag.flaggable_type.tableize).should eq 1
23
+ end
24
+ end
25
+
26
+ describe "when destroying" do
27
+ let!(:flag) { create :flag_in_flag }
28
+ let!(:flag2) { create :flag_in_flag, feature: flag.feature }
29
+
30
+ before do
31
+ flag2.destroy
32
+ end
33
+
34
+ it "decrements its feature's flag_in_count" do
35
+ flag.reload.feature.flag_in_count_for(flag.flaggable_type.tableize).should eq 1
36
+ end
37
+ end
38
+ end
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
 
3
3
  describe Detour::Flag do
4
4
  it { should belong_to :feature }
5
- it { should validate_presence_of :feature_id }
5
+ it { should validate_presence_of :feature }
6
6
  it { should validate_presence_of :flaggable_type }
7
7
  it { should allow_mass_assignment_of :flaggable_type }
8
8
  end
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+
3
+ describe Detour::OptOutFlag do
4
+ it { should be_a Detour::Flag }
5
+ it { should belong_to :flaggable }
6
+ it { should validate_presence_of :flaggable }
7
+ it { should allow_mass_assignment_of :flaggable }
8
+
9
+ it "validates uniquness of feature_id on flaggable" do
10
+ user = create :user
11
+ flag = create :opt_out_flag, flaggable: user
12
+ flag2 = build :opt_out_flag, flaggable: user, feature: flag.feature
13
+
14
+ flag2.should_not be_valid
15
+ flag2.errors.full_messages.should eq ["Feature has already been taken"]
16
+ end
17
+
18
+ describe "when creating" do
19
+ let(:flag) { create :opt_out_flag }
20
+
21
+ it "increments its feature's opt_out_count" do
22
+ flag.reload.feature.opt_out_count_for(flag.flaggable_type.tableize).should eq 1
23
+ end
24
+ end
25
+
26
+ describe "when destroying" do
27
+ let!(:flag) { create :opt_out_flag }
28
+ let!(:flag2) { create :opt_out_flag, feature: flag.feature }
29
+
30
+ before do
31
+ flag2.destroy
32
+ end
33
+
34
+ it "decrements its feature's opt_out_count" do
35
+ flag.reload.feature.opt_out_count_for(flag.flaggable_type.tableize).should eq 1
36
+ end
37
+ end
38
+ end
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Detour::PercentageFlag do
4
- subject { Detour::PercentageFlag.new(feature_id: 1, flaggable_type: "User") }
4
+ subject { build :percentage_flag }
5
5
 
6
6
  it { should be_a Detour::Flag }
7
7
  it { should validate_numericality_of(:percentage).is_greater_than(0).is_less_than_or_equal_to(100) }