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
@@ -0,0 +1,118 @@
1
+ require "spec_helper"
2
+
3
+ describe "counting flaggable flags" do
4
+ let!(:flag) { create :flag_in_flag }
5
+
6
+ before do
7
+ visit "/detour/flags/users"
8
+ end
9
+
10
+ it "displays the defined groups" do
11
+ within "tr#feature_#{flag.feature.id} td.flag-in-count" do
12
+ page.should have_content 1
13
+ end
14
+ end
15
+ end
16
+
17
+ describe "listing flag_in_flags" do
18
+ let!(:flag) { create :flag_in_flag }
19
+
20
+ before do
21
+ User.instance_variable_set "@detour_flaggable_find_by", :email
22
+ visit "/detour/flag-ins/#{flag.feature.name}/users"
23
+ end
24
+
25
+ it "displays the flagged-in model's find-by" do
26
+ page.should have_content flag.flaggable.email
27
+ end
28
+ end
29
+
30
+ describe "creating flag-ins", js: true do
31
+ let(:user) { create :user }
32
+ let!(:feature) { create :feature }
33
+
34
+ before do
35
+ User.instance_variable_set "@detour_flaggable_find_by", :email
36
+ visit "/detour/flag-ins/#{feature.name}/users"
37
+ page.find("[data-target='#create-flaggable-flag']").click
38
+ end
39
+
40
+ context "when creating multiple flag-ins" do
41
+ let(:user2) { create :user, email: "another_user@example.com" }
42
+
43
+ context "when successful" do
44
+ before do
45
+ fill_in "ids", with: [user.email, user2.email].join(",")
46
+ click_button "Create Flag-in"
47
+ end
48
+
49
+ it "displays a success message" do
50
+ page.should have_content "Users #{user.email}, #{user2.email} have been flagged in to #{feature.name}"
51
+ end
52
+ end
53
+
54
+ context "when unsuccessful" do
55
+ before do
56
+ fill_in "ids", with: "#{user.email},foo"
57
+ click_button "Create Flag-in"
58
+ end
59
+
60
+ it "displays error messages" do
61
+ page.should have_content "Couldn't find User with email = foo"
62
+ end
63
+ end
64
+ end
65
+
66
+ context "when creating single flag-ins" do
67
+ context "when successful" do
68
+ before do
69
+ fill_in "ids", with: user.email
70
+ click_button "Create Flag-in"
71
+ end
72
+
73
+ it "displays a success message" do
74
+ page.should have_content "User #{user.email} has been flagged in to #{feature.name}"
75
+ end
76
+
77
+ it "renders the new flag-in" do
78
+ within "table" do
79
+ page.should have_content user.email
80
+ end
81
+ end
82
+ end
83
+
84
+ context "when unsuccessful" do
85
+ before do
86
+ fill_in "ids", with: "foo"
87
+ click_button "Create Flag-in"
88
+ end
89
+
90
+ it "displays error messages" do
91
+ page.should have_content "Couldn't find User with email = foo"
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ describe "destroying flag-ins", js: true do
98
+ let!(:flag) { create :flag_in_flag }
99
+
100
+ before do
101
+ visit "/detour/flag-ins/#{flag.feature.name}/users"
102
+ page.find(".delete-flag").click
103
+ click_link "Delete Flag-in"
104
+ end
105
+
106
+ it "displays a flash message" do
107
+ page.should have_content "#{flag.feature.name} flag-in for User #{flag.flaggable.send flag.flaggable_type.constantize.detour_flaggable_find_by} has been deleted."
108
+ end
109
+
110
+ it "destroys the flag-in" do
111
+ expect { flag.reload }.to raise_error ActiveRecord::RecordNotFound
112
+ end
113
+
114
+
115
+ it "removes the flag from the list" do
116
+ page.should_not have_content flag.flaggable.email
117
+ end
118
+ end
@@ -0,0 +1,49 @@
1
+ require "spec_helper"
2
+
3
+ describe "listing defined groups" do
4
+ before do
5
+ Detour.config.define_user_group :admins do |user|
6
+ end
7
+
8
+ visit "/detour/flags/users"
9
+ end
10
+
11
+ it "displays the defined groups" do
12
+ page.should have_content "admins"
13
+ end
14
+ end
15
+
16
+ describe "creating defined group flags" do
17
+ let!(:feature) { create :feature }
18
+
19
+ before do
20
+ Detour.config.define_user_group :admins do |user|
21
+ end
22
+
23
+ visit "/detour/flags/users"
24
+ check "features[#{feature.name}][users_group_flags_attributes[admins]][to_keep]"
25
+ click_button "Save Changes"
26
+ end
27
+
28
+ it "creates the group flag" do
29
+ feature.reload.users_group_flags.first.group_name.should eq "admins"
30
+ end
31
+ end
32
+
33
+ describe "removing defined group flags" do
34
+ let(:feature) { create :feature }
35
+ let!(:group_flag) { create :group_flag, feature: feature, group_name: "admins" }
36
+
37
+ before do
38
+ Detour.config.define_user_group :admins do |user|
39
+ end
40
+
41
+ visit "/detour/flags/users"
42
+ uncheck "features[#{feature.name}][users_group_flags_attributes[admins]][to_keep]"
43
+ click_button "Save Changes"
44
+ end
45
+
46
+ it "creates the group flag" do
47
+ feature.reload.users_group_flags.should be_empty
48
+ end
49
+ end
@@ -0,0 +1,11 @@
1
+ require "spec_helper"
2
+
3
+ describe "the home page" do
4
+ before do
5
+ visit "/detour"
6
+ end
7
+
8
+ it "displays the name of the gem" do
9
+ page.should have_content "Detour"
10
+ end
11
+ end
@@ -0,0 +1,105 @@
1
+ require "spec_helper"
2
+
3
+ describe "counting opt out flags" do
4
+ let!(:flag) { create :opt_out_flag }
5
+
6
+ before do
7
+ visit "/detour/flags/users"
8
+ end
9
+
10
+ it "displays the defined groups" do
11
+ within "tr#feature_#{flag.feature.id} td.opt-out-count" do
12
+ page.should have_content 1
13
+ end
14
+ end
15
+ end
16
+
17
+ describe "creating opt-outs", js: true do
18
+ let(:user) { create :user }
19
+ let!(:feature) { create :feature }
20
+
21
+ before do
22
+ User.instance_variable_set "@detour_flaggable_find_by", :email
23
+ visit "/detour/opt-outs/#{feature.name}/users"
24
+ page.find("[data-target='#create-flaggable-flag']").click
25
+ end
26
+
27
+ context "when creating multiple opt-outs" do
28
+ let(:user2) { create :user, email: "another_user@example.com" }
29
+
30
+ context "when successful" do
31
+ before do
32
+ fill_in "ids", with: [user.email, user2.email].join(",")
33
+ click_button "Create Opt-out"
34
+ end
35
+
36
+ it "displays a success message" do
37
+ page.should have_content "Users #{user.email}, #{user2.email} have been opted out of #{feature.name}"
38
+ end
39
+ end
40
+
41
+ context "when unsuccessful" do
42
+ before do
43
+ fill_in "ids", with: "#{user.email},foo"
44
+ click_button "Create Opt-out"
45
+ end
46
+
47
+ it "displays error messages" do
48
+ page.should have_content "Couldn't find User with email = foo"
49
+ end
50
+ end
51
+ end
52
+
53
+ context "when creating single opt-outs" do
54
+ context "when successful" do
55
+ before do
56
+ fill_in "ids", with: user.email
57
+ click_button "Create Opt-out"
58
+ end
59
+
60
+ it "displays a success message" do
61
+ page.should have_content "User #{user.email} has been opted out of #{feature.name}"
62
+ end
63
+
64
+ it "renders the new opt-out" do
65
+ within "table" do
66
+ page.should have_content user.email
67
+ end
68
+ end
69
+ end
70
+
71
+ context "when unsuccessful" do
72
+ before do
73
+ fill_in "ids", with: "foo"
74
+ click_button "Create Opt-out"
75
+ end
76
+
77
+ it "displays error messages" do
78
+ page.should have_content "Couldn't find User with email = foo"
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ describe "destroying opt-outs", js: true do
85
+ let!(:flag) { create :opt_out_flag }
86
+
87
+ before do
88
+ visit "/detour/opt-outs/#{flag.feature.name}/users"
89
+ page.find(".delete-flag").click
90
+ click_link "Delete Opt-out"
91
+ end
92
+
93
+ it "displays a flash message" do
94
+ page.should have_content "#{flag.feature.name} opt-out for User #{flag.flaggable.send flag.flaggable_type.constantize.detour_flaggable_find_by} has been deleted."
95
+ end
96
+
97
+ it "destroys the opt-out" do
98
+ expect { flag.reload }.to raise_error ActiveRecord::RecordNotFound
99
+ end
100
+
101
+
102
+ it "removes the flag from the list" do
103
+ page.should_not have_content flag.flaggable.email
104
+ end
105
+ end
@@ -0,0 +1,63 @@
1
+ require "spec_helper"
2
+
3
+ describe "listing percentage flags for a type" do
4
+ let(:feature) { create :feature }
5
+ let!(:percentage_flag) { create :percentage_flag, feature: feature }
6
+
7
+ before do
8
+ visit "/detour/flags/users"
9
+ end
10
+
11
+ it "displays the percentage flag for the feature" do
12
+ page.find("#features_#{feature.name}_users_percentage_flag_attributes_percentage").value.to_i.should eq percentage_flag.percentage
13
+ end
14
+ end
15
+
16
+ describe "creating a percentage flag" do
17
+ let!(:feature) { create :feature }
18
+
19
+ before do
20
+ visit "/detour/flags/users"
21
+ end
22
+
23
+ context "when successful" do
24
+ before do
25
+ fill_in "features[#{feature.name}][users_percentage_flag_attributes][percentage]", with: "50"
26
+ click_button "Save Changes"
27
+ end
28
+
29
+ it "saves the new feature" do
30
+ feature.users_percentage_flag.percentage.should eq 50
31
+ end
32
+
33
+ it "displays a success message" do
34
+ page.should have_content "Your flags have been successfully updated."
35
+ end
36
+ end
37
+
38
+ context "when unsuccessful" do
39
+ before do
40
+ fill_in "features[#{feature.name}][users_percentage_flag_attributes][percentage]", with: "foo"
41
+ click_button "Save Changes"
42
+ end
43
+
44
+ it "displays error messages" do
45
+ page.should have_content "#{feature.name}: Users percentage flag percentage is not a number"
46
+ end
47
+ end
48
+ end
49
+
50
+ describe "destroying a percentage flag" do
51
+ let(:feature) { create :feature }
52
+ let!(:percentage_flag) { create :percentage_flag, feature: feature }
53
+
54
+ before do
55
+ visit "/detour/flags/users"
56
+ fill_in "features[#{feature.name}][users_percentage_flag_attributes][percentage]", with: ""
57
+ click_button "Save Changes"
58
+ end
59
+
60
+ it "destroys the percentage flag" do
61
+ feature.users_percentage_flag.should be_nil
62
+ end
63
+ end
@@ -7,7 +7,7 @@ describe "group rollouts" do
7
7
 
8
8
  describe "creating a group rollout" do
9
9
  before do
10
- Detour::Feature.define_user_group "foo_users" do |user|
10
+ Detour.config.define_user_group "foo_users" do |user|
11
11
  user.name == "foo"
12
12
  end
13
13
  end
@@ -0,0 +1,45 @@
1
+ require "spec_helper"
2
+
3
+ describe Detour::ActsAsFlaggable do
4
+ subject { User.new }
5
+
6
+ it { should have_many :flag_in_flags }
7
+ it { should have_many :opt_out_flags }
8
+ it { should have_many(:features).through(:flag_in_flags) }
9
+
10
+ it "includes Detour::Flaggable" do
11
+ subject.class.ancestors.should include Detour::Flaggable
12
+ end
13
+
14
+ describe "#acts_as_flaggable" do
15
+ describe "Detour::Feature associations" do
16
+ subject { Detour::Feature.new }
17
+ it { should have_many(:users_group_flags).class_name("Detour::GroupFlag").dependent(:destroy) }
18
+ it { should allow_mass_assignment_of(:users_group_flags_attributes) }
19
+ it { should accept_nested_attributes_for(:users_group_flags) }
20
+
21
+ it { should have_one(:users_percentage_flag).class_name("Detour::PercentageFlag").dependent(:destroy) }
22
+ it { should allow_mass_assignment_of(:users_percentage_flag_attributes) }
23
+ it { should accept_nested_attributes_for(:users_percentage_flag) }
24
+
25
+ it { should have_many(:users_flag_ins).class_name("Detour::FlagInFlag").dependent(:destroy) }
26
+ it { should have_many(:users_opt_outs).class_name("Detour::OptOutFlag").dependent(:destroy) }
27
+ end
28
+
29
+ context "when given a :find_by parameter" do
30
+ class Foo < ActiveRecord::Base
31
+ acts_as_flaggable find_by: :email
32
+ end
33
+
34
+ it "sets the appropriate class variable on the class" do
35
+ Foo.instance_variable_get("@detour_flaggable_find_by").should eq :email
36
+ end
37
+ end
38
+
39
+ context "when not given a :find_by parameter" do
40
+ it "uses the default :id value for flaggable_find_by" do
41
+ User.instance_variable_get("@detour_flaggable_find_by").should eq :id
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+
3
+ describe Detour::Configuration do
4
+ describe ".define_group_for_class" do
5
+ let(:block) { Proc.new {} }
6
+
7
+ before do
8
+ subject.send :define_group_for_class, "User", "user_id_1", &block
9
+ end
10
+
11
+ it "defines a group for the given class" do
12
+ subject.defined_groups["User"].should eq({ "user_id_1" => block })
13
+ end
14
+ end
15
+
16
+ describe ".define_{klass}_group" do
17
+ let(:block) { Proc.new {} }
18
+ it "defines a group for the given class" do
19
+ subject.should_receive(:define_group_for_class).with("User", :id_is_1)
20
+ subject.define_user_group :id_is_1, block
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,84 @@
1
+ require "spec_helper"
2
+
3
+ describe Detour::FlagForm do
4
+ subject { Detour::FlagForm.new("users") }
5
+
6
+ let!(:feature) { create :feature, name: "foo_feature" }
7
+
8
+ describe "#features" do
9
+ before do
10
+ Detour.config.grep_dirs = ["spec/dummy/app/**/*.{rb,erb}"]
11
+ end
12
+
13
+ it "returns every feature including lines" do
14
+ subject.features.collect(&:name).should eq Detour::Feature.with_lines.collect(&:name)
15
+ end
16
+ end
17
+
18
+ describe "#group_names" do
19
+ before do
20
+ Detour.config.define_user_group :admins do |user|
21
+ end
22
+ end
23
+
24
+ it "returns the name of defined groups" do
25
+ subject.group_names.should eq ["admins"]
26
+ end
27
+ end
28
+
29
+ describe "#update_attributes" do
30
+ let(:features_params) do
31
+ {
32
+ "foo_feature" => { users_percentage_flag_attributes: {} }
33
+ }
34
+ end
35
+
36
+ it "updates the feature attributes" do
37
+ Detour::Feature.any_instance.should_receive :assign_attributes
38
+ Detour::Feature.any_instance.stub(:changed_for_autosave?) { true }
39
+ Detour::Feature.any_instance.should_receive :save
40
+ subject.update_attributes({ features: features_params })
41
+ end
42
+
43
+ context "when successful" do
44
+ it "returns true" do
45
+ subject.update_attributes({ features: features_params }).should be_true
46
+ end
47
+ end
48
+
49
+ context "when unsuccessful" do
50
+ it "returns nil" do
51
+ subject.update_attributes({ features: { "foo_feature" => { users_percentage_flag_attributes: { percentage: "foo" } } } }).should be_nil
52
+ end
53
+
54
+ it "uses a transaction" do
55
+ feature2 = create :feature, name: "foo_feature_2"
56
+
57
+ subject.update_attributes({ features: {
58
+ "foo_feature_2" => { users_percentage_flag_attributes: { percentage: 10 } },
59
+ "foo_feature" => { users_percentage_flag_attributes: { percentage: "foo" } }
60
+ } })
61
+
62
+ feature2.users_percentage_flag.should be_nil
63
+ end
64
+ end
65
+
66
+ context "when a percentage flag should be removed" do
67
+ let!(:percentage_flag) { create :percentage_flag, feature: feature }
68
+
69
+ let(:features_params) do
70
+ {
71
+ "foo_feature" => { users_percentage_flag_attributes: { percentage: "" } },
72
+ }
73
+ end
74
+
75
+ before do
76
+ subject.update_attributes({ features: features_params });
77
+ end
78
+
79
+ it "destroys the percentage flag" do
80
+ feature.reload.users_percentage_flag.should be_nil
81
+ end
82
+ end
83
+ end
84
+ end
@@ -24,29 +24,29 @@ describe Detour::Flaggable do
24
24
  end
25
25
 
26
26
  describe "#has_feature?" do
27
- let(:user) { User.create(name: "foo") }
28
- let(:feature) { Detour::Feature.create(name: "bar") }
27
+ let(:user) { create :user }
28
+ let(:feature) { create :feature }
29
29
 
30
30
  it "memoizes found features" do
31
31
  Detour::Feature.stub(:find_by_name) { feature }
32
- feature.flaggable_flags.create(flaggable: user)
32
+ feature.flag_in_flags.create(flaggable: user)
33
33
 
34
34
  feature.should_receive(:match?).with(user).and_return(true)
35
- user.has_feature?(:bar)
35
+ user.has_feature?(feature.name)
36
36
 
37
37
  feature.should_not_receive(:match?).with(user)
38
- user.has_feature?(:bar)
38
+ user.has_feature?(feature.name)
39
39
  end
40
40
 
41
41
  context "when given a block" do
42
42
  context "and the user is flagged in" do
43
43
  before do
44
- feature.flaggable_flags.create(flaggable: user)
44
+ feature.flag_in_flags.create(flaggable: user)
45
45
  end
46
46
 
47
47
  it "calls the block" do
48
48
  foo = "foo"
49
- user.has_feature?(:bar) { foo = "bar" }
49
+ user.has_feature?(feature.name) { foo = "bar" }
50
50
  foo.should eq "bar"
51
51
  end
52
52
 
@@ -64,7 +64,7 @@ describe Detour::Flaggable do
64
64
  context "when the block raises an exception" do
65
65
  it "increments the failure_count of the feature" do
66
66
  begin
67
- user.has_feature? :bar do
67
+ user.has_feature? feature.name do
68
68
  raise "This is an exception"
69
69
  end
70
70
  rescue
@@ -74,7 +74,7 @@ describe Detour::Flaggable do
74
74
 
75
75
  it "raises the exception" do
76
76
  expect do
77
- user.has_feature? :bar do
77
+ user.has_feature? feature.name do
78
78
  raise "This is an exception"
79
79
  end
80
80
  end.to raise_error "This is an exception"
@@ -85,7 +85,7 @@ describe Detour::Flaggable do
85
85
  context "and the user is not flagged in" do
86
86
  it "does not call the block" do
87
87
  foo = "foo"
88
- user.has_feature?(:bar) { foo = "bar" }
88
+ user.has_feature?(feature.name) { foo = "bar" }
89
89
  foo.should eq "foo"
90
90
  end
91
91
  end
@@ -93,30 +93,30 @@ describe Detour::Flaggable do
93
93
 
94
94
  context "when the user is not flagged in" do
95
95
  it "returns false" do
96
- user.has_feature?(:bar).should be_false
96
+ user.has_feature?(feature.name).should be_false
97
97
  end
98
98
  end
99
99
 
100
100
  context "when the user is flagged in" do
101
101
  context "and the user is opted out" do
102
102
  before do
103
- feature.flaggable_flags.create(flaggable: user)
103
+ feature.flag_in_flags.create(flaggable: user)
104
104
  feature.opt_out_flags.create(flaggable: user)
105
105
  end
106
106
 
107
107
  it "returns false" do
108
- user.has_feature?(:bar).should be_false
108
+ user.has_feature?(feature.name).should be_false
109
109
  end
110
110
  end
111
111
 
112
112
  context "and the user is not opted out" do
113
113
  context "and the user is flagged in individually" do
114
114
  before do
115
- feature.flaggable_flags.create(flaggable: user)
115
+ feature.flag_in_flags.create(flaggable: user)
116
116
  end
117
117
 
118
118
  it "returns true" do
119
- user.has_feature?(:bar).should be_true
119
+ user.has_feature?(feature.name).should be_true
120
120
  end
121
121
  end
122
122
 
@@ -126,21 +126,21 @@ describe Detour::Flaggable do
126
126
  end
127
127
 
128
128
  it "returns true" do
129
- user.has_feature?(:bar).should be_true
129
+ user.has_feature?(feature.name).should be_true
130
130
  end
131
131
  end
132
132
 
133
133
  context "and the user is flagged in via a group" do
134
134
  before do
135
- Detour::Feature.define_user_group "name_foo" do |user|
136
- user.name == "foo"
135
+ Detour.config.define_user_group "name_foo" do |_user|
136
+ _user.name == user.name
137
137
  end
138
138
 
139
139
  feature.group_flags.create(flaggable_type: "User", group_name: "name_foo")
140
140
  end
141
141
 
142
142
  it "returns true" do
143
- user.has_feature?(:bar).should be_true
143
+ user.has_feature?(feature.name).should be_true
144
144
  end
145
145
  end
146
146
  end