detour 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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) }