merit 2.4.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +3 -35
- data/NEWS.md +31 -0
- data/README.md +15 -3
- data/RELEASING.md +16 -0
- data/Rakefile +13 -1
- data/app/models/merit/badge.rb +2 -19
- data/lib/merit.rb +13 -35
- data/lib/merit/{rules_badge_methods.rb → badge_rules_methods.rb} +0 -0
- data/lib/merit/base_target_finder.rb +1 -6
- data/lib/merit/{model_additions.rb → class_methods.rb} +2 -19
- data/lib/merit/controller_extensions.rb +13 -30
- data/lib/{generators → merit/generators}/active_record/install_generator.rb +12 -8
- data/lib/{generators → merit/generators}/active_record/merit_generator.rb +7 -3
- data/lib/{generators → merit/generators}/active_record/remove_generator.rb +9 -5
- data/lib/{generators/active_record/templates/add_merit_fields_to_model.rb → merit/generators/active_record/templates/add_merit_fields_to_model.erb} +1 -1
- data/lib/{generators/active_record/templates/create_badges_sashes.rb → merit/generators/active_record/templates/create_badges_sashes.erb} +1 -1
- data/lib/{generators/active_record/templates/create_merit_actions.rb → merit/generators/active_record/templates/create_merit_actions.erb} +2 -2
- data/lib/{generators/active_record/templates/create_merit_activity_logs.rb → merit/generators/active_record/templates/create_merit_activity_logs.erb} +1 -1
- data/lib/merit/generators/active_record/templates/create_sashes.erb +7 -0
- data/lib/{generators/active_record/templates/create_scores_and_points.rb → merit/generators/active_record/templates/create_scores_and_points.erb} +2 -2
- data/lib/{generators/active_record/templates/remove_merit_fields_from_model.rb → merit/generators/active_record/templates/remove_merit_fields_from_model.erb} +1 -1
- data/lib/{generators/active_record/templates/remove_merit_tables.rb → merit/generators/active_record/templates/remove_merit_tables.erb} +1 -1
- data/lib/merit/generators/install_generator.rb +18 -0
- data/lib/{generators/merit → merit/generators}/merit_generator.rb +3 -1
- data/lib/{generators/merit → merit/generators}/remove_generator.rb +3 -1
- data/lib/{generators/merit/templates/merit.rb → merit/generators/templates/merit.erb} +0 -3
- data/lib/{generators/merit/templates/merit_badge_rules.rb → merit/generators/templates/merit_badge_rules.erb} +0 -0
- data/lib/{generators/merit/templates/merit_point_rules.rb → merit/generators/templates/merit_point_rules.erb} +0 -0
- data/lib/{generators/merit/templates/merit_rank_rules.rb → merit/generators/templates/merit_rank_rules.erb} +0 -0
- data/{app/models/merit/action.rb → lib/merit/models/action_concern.rb} +12 -10
- data/lib/merit/models/active_record/action.rb +11 -0
- data/lib/merit/models/active_record/{merit/activity_log.rb → activity_log.rb} +4 -6
- data/lib/merit/models/active_record/{merit/badges_sash.rb → badges_sash.rb} +4 -4
- data/lib/merit/models/active_record/{merit/sash.rb → sash.rb} +5 -2
- data/lib/merit/models/active_record/{merit/score.rb → score.rb} +4 -1
- data/lib/merit/models/badges_sash_concern.rb +13 -0
- data/lib/merit/models/base/badges_sash.rb +1 -1
- data/lib/merit/models/base/sash.rb +1 -1
- data/lib/merit/models/sash_concern.rb +53 -0
- data/lib/merit/{rules_points_methods.rb → point_rules_methods.rb} +0 -0
- data/lib/merit/{rules_rank_methods.rb → rank_rules_methods.rb} +3 -18
- data/merit.gemspec +7 -5
- data/test/dummy/app/controllers/comments_controller.rb +1 -1
- data/test/dummy/app/controllers/registrations_controller.rb +1 -1
- data/test/dummy/app/models/address.rb +1 -12
- data/test/dummy/app/models/comment.rb +3 -25
- data/test/dummy/app/models/user.rb +1 -18
- data/test/dummy/config/application.rb +8 -10
- data/test/dummy/config/application_api_only.rb +28 -0
- data/test/dummy/config/environment_api_only.rb +7 -0
- data/test/dummy/config/environments/test.rb +1 -1
- data/test/dummy/config/initializers/new_framework_defaults.rb +3 -0
- data/test/dummy/db/migrate/20110421191249_create_users.rb +2 -2
- data/test/dummy/db/migrate/20110421191250_create_comments.rb +2 -2
- data/test/dummy/db/migrate/20120318022220_add_fields_to_users.rb +1 -1
- data/test/dummy/db/migrate/20130321082817_add_fields_to_comments.rb +1 -1
- data/test/dummy/db/migrate/20130329224406_create_merit_actions.rb +2 -2
- data/test/dummy/db/migrate/20130329224407_create_merit_activity_logs.rb +1 -1
- data/test/dummy/db/migrate/20130329224408_create_sashes.rb +2 -2
- data/test/dummy/db/migrate/20130329224409_create_badges_sashes.rb +1 -1
- data/test/dummy/db/migrate/20130329224410_create_scores_and_points.rb +1 -1
- data/test/dummy/db/migrate/20140211144001_create_addresses.rb +1 -1
- data/test/dummy/db/migrate/20140819133931_add_target_data_to_merit_actions.rb +1 -1
- data/test/dummy/db/schema.rb +55 -59
- data/test/integration/navigation_test.rb +2 -2
- data/test/test_helper.rb +11 -12
- data/test/unit/base_target_finder_test.rb +7 -26
- data/test/unit/merit_unit_test.rb +13 -17
- data/test/unit/rule_unit_test.rb +15 -8
- data/test/unit/rules_matcher_test.rb +9 -6
- data/test/unit/sash_finder_test.rb +5 -5
- data/test/unit/score_test.rb +1 -1
- data/test/unit/target_finder_test.rb +13 -13
- metadata +61 -70
- data/UPGRADING.md +0 -256
- data/lib/generators/active_record/templates/add_target_data_to_merit_actions.rb +0 -5
- data/lib/generators/active_record/templates/create_sashes.rb +0 -7
- data/lib/generators/active_record/upgrade_generator.rb +0 -36
- data/lib/generators/merit/install_generator.rb +0 -16
- data/lib/generators/merit/upgrade_generator.rb +0 -7
- data/lib/merit/models/active_record/merit/action.rb +0 -12
- data/lib/merit/models/mongoid/merit/action.rb +0 -18
- data/lib/merit/models/mongoid/merit/activity_log.rb +0 -11
- data/lib/merit/models/mongoid/merit/badges_sash.rb +0 -22
- data/lib/merit/models/mongoid/merit/sash.rb +0 -30
- data/lib/merit/models/mongoid/merit/score.rb +0 -45
- data/test/dummy/db/migrate/20140906225844_create_players.rb +0 -8
- data/test/dummy/public/javascripts/application.js +0 -2
- data/test/dummy/public/javascripts/controls.js +0 -965
- data/test/dummy/public/javascripts/dragdrop.js +0 -974
- data/test/dummy/public/javascripts/effects.js +0 -1123
- data/test/dummy/public/javascripts/prototype.js +0 -6001
- data/test/dummy/public/javascripts/rails.js +0 -191
- data/test/orm/active_record.rb +0 -2
- data/test/orm/mongoid.rb +0 -6
- data/test/orm_models/active_record.rb +0 -11
- data/test/orm_models/mongoid.rb +0 -15
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'rails/generators/active_record'
|
2
2
|
|
3
|
-
module
|
4
|
-
module Generators
|
5
|
-
class MeritGenerator < ActiveRecord::Generators::Base
|
3
|
+
module Merit
|
4
|
+
module Generators::ActiveRecord
|
5
|
+
class MeritGenerator < ::ActiveRecord::Generators::Base
|
6
6
|
include Rails::Generators::Migration
|
7
7
|
|
8
8
|
source_root File.expand_path('../templates', __FILE__)
|
@@ -16,6 +16,10 @@ module ActiveRecord
|
|
16
16
|
migration_template 'add_merit_fields_to_model.rb',
|
17
17
|
"db/migrate/add_merit_fields_to_#{table_name}.rb"
|
18
18
|
end
|
19
|
+
|
20
|
+
def migration_version
|
21
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
22
|
+
end
|
19
23
|
end
|
20
24
|
end
|
21
25
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'rails/generators/active_record'
|
2
2
|
|
3
|
-
module
|
4
|
-
module Generators
|
5
|
-
class RemoveGenerator < ActiveRecord::Generators::Base
|
3
|
+
module Merit
|
4
|
+
module Generators::ActiveRecord
|
5
|
+
class RemoveGenerator < ::ActiveRecord::Generators::Base
|
6
6
|
include Rails::Generators::Migration
|
7
7
|
|
8
8
|
source_root File.expand_path('../templates', __FILE__)
|
@@ -13,14 +13,18 @@ module ActiveRecord
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def copy_migrations_and_model
|
16
|
-
migration_template 'remove_merit_tables.
|
16
|
+
migration_template 'remove_merit_tables.erb',
|
17
17
|
'db/migrate/remove_merit_tables.rb'
|
18
18
|
|
19
19
|
migration_template(
|
20
|
-
'remove_merit_fields_from_model.
|
20
|
+
'remove_merit_fields_from_model.erb',
|
21
21
|
"db/migrate/remove_merit_fields_from_#{table_name}.rb"
|
22
22
|
)
|
23
23
|
end
|
24
|
+
|
25
|
+
def migration_version
|
26
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
27
|
+
end
|
24
28
|
end
|
25
29
|
end
|
26
30
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class AddMeritFieldsTo<%= table_name.camelize %> < ActiveRecord::Migration
|
1
|
+
class AddMeritFieldsTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
|
2
2
|
def change
|
3
3
|
add_column :<%= table_name %>, :sash_id, :integer
|
4
4
|
add_column :<%= table_name %>, :level, :integer, :default => 0
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class CreateMeritActions < ActiveRecord::Migration
|
1
|
+
class CreateMeritActions < ActiveRecord::Migration<%= migration_version %>
|
2
2
|
def change
|
3
3
|
create_table :merit_actions do |t|
|
4
4
|
t.integer :user_id
|
@@ -9,7 +9,7 @@ class CreateMeritActions < ActiveRecord::Migration
|
|
9
9
|
t.integer :target_id
|
10
10
|
t.text :target_data
|
11
11
|
t.boolean :processed, default: false
|
12
|
-
t.timestamps
|
12
|
+
t.timestamps null: false
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class CreateScoresAndPoints < ActiveRecord::Migration
|
1
|
+
class CreateScoresAndPoints < ActiveRecord::Migration<%= migration_version %>
|
2
2
|
def change
|
3
3
|
create_table :merit_scores do |t|
|
4
4
|
t.references :sash
|
@@ -7,7 +7,7 @@ class CreateScoresAndPoints < ActiveRecord::Migration
|
|
7
7
|
|
8
8
|
create_table :merit_score_points do |t|
|
9
9
|
t.references :score
|
10
|
-
t.
|
10
|
+
t.bigint :num_points, default: 0
|
11
11
|
t.string :log
|
12
12
|
t.datetime :created_at
|
13
13
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class RemoveMeritFieldsFrom<%= table_name.camelize %> < ActiveRecord::Migration
|
1
|
+
class RemoveMeritFieldsFrom<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
|
2
2
|
def self.up
|
3
3
|
remove_column :<%= table_name %>, :sash_id
|
4
4
|
remove_column :<%= table_name %>, :level
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "rails/generators"
|
2
|
+
|
3
|
+
module Merit
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < ::Rails::Generators::Base
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
hook_for :orm
|
8
|
+
|
9
|
+
desc 'Copy config and rules files'
|
10
|
+
def copy_migrations_and_model
|
11
|
+
template 'merit.erb', 'config/initializers/merit.rb'
|
12
|
+
template 'merit_badge_rules.erb', 'app/models/merit/badge_rules.rb'
|
13
|
+
template 'merit_point_rules.erb', 'app/models/merit/point_rules.rb'
|
14
|
+
template 'merit_rank_rules.erb', 'app/models/merit/rank_rules.rb'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -3,9 +3,6 @@ Merit.setup do |config|
|
|
3
3
|
# Check rules on each request or in background
|
4
4
|
# config.checks_on_each_request = true
|
5
5
|
|
6
|
-
# Define ORM. Could be :active_record (default) and :mongoid
|
7
|
-
# config.orm = :active_record
|
8
|
-
|
9
6
|
# Add application observers to get notifications when reputation changes.
|
10
7
|
# config.add_observer 'MyObserverClassName'
|
11
8
|
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require_dependency "merit/models/#{Merit.orm}/merit/action"
|
2
|
-
|
3
1
|
# Merit::Action general schema
|
4
2
|
# ______________________________________________________________
|
5
3
|
# source | action | target
|
@@ -12,10 +10,14 @@ require_dependency "merit/models/#{Merit.orm}/merit/action"
|
|
12
10
|
# ______________________________________________________________
|
13
11
|
#
|
14
12
|
# Rules relate to merit_actions by action name ('controller#action' string)
|
15
|
-
module Merit
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
module Merit::Models
|
14
|
+
module ActionConcern
|
15
|
+
extend ActiveSupport::Concern
|
16
|
+
|
17
|
+
class_methods do
|
18
|
+
def check_unprocessed
|
19
|
+
where(processed: false).find_each(&:check_all_rules)
|
20
|
+
end
|
19
21
|
end
|
20
22
|
|
21
23
|
# Check rules defined for a merit_action
|
@@ -23,16 +25,16 @@ module Merit
|
|
23
25
|
mark_as_processed!
|
24
26
|
return if had_errors
|
25
27
|
|
26
|
-
check_rules rules_matcher.select_from(AppBadgeRules), :badges
|
27
|
-
check_rules rules_matcher.select_from(AppPointRules), :points
|
28
|
+
check_rules rules_matcher.select_from(Merit::AppBadgeRules), :badges
|
29
|
+
check_rules rules_matcher.select_from(Merit::AppPointRules), :points
|
28
30
|
end
|
29
31
|
|
30
32
|
private
|
31
33
|
|
32
34
|
def check_rules(rules_array, badges_or_points)
|
33
35
|
rules_array.each do |rule|
|
34
|
-
judge = Judge.new
|
35
|
-
judge.
|
36
|
+
judge = Merit::Judge.new(rule, action: self)
|
37
|
+
judge.public_send(:"apply_#{badges_or_points}")
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Merit::Models::ActiveRecord
|
2
|
+
class Action < ActiveRecord::Base
|
3
|
+
include Merit::Models::ActionConcern
|
4
|
+
|
5
|
+
self.table_name = :merit_actions
|
6
|
+
|
7
|
+
has_many :activity_logs, class_name: 'Merit::ActivityLog'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Merit::Action < Merit::Models::ActiveRecord::Action; end
|
@@ -1,13 +1,11 @@
|
|
1
|
-
module Merit
|
1
|
+
module Merit::Models::ActiveRecord
|
2
2
|
class ActivityLog < ActiveRecord::Base
|
3
3
|
self.table_name = :merit_activity_logs
|
4
4
|
|
5
5
|
belongs_to :action, class_name: 'Merit::Action'
|
6
|
-
belongs_to :related_change, polymorphic: true
|
6
|
+
belongs_to :related_change, polymorphic: true, optional: true
|
7
7
|
has_one :sash, through: :related_change
|
8
|
-
|
9
|
-
if show_attr_accessible?
|
10
|
-
attr_accessible :action_id, :related_change, :description, :created_at
|
11
|
-
end
|
12
8
|
end
|
13
9
|
end
|
10
|
+
|
11
|
+
class Merit::ActivityLog < Merit::Models::ActiveRecord::ActivityLog; end
|
@@ -1,13 +1,13 @@
|
|
1
|
-
module Merit
|
1
|
+
module Merit::Models::ActiveRecord
|
2
2
|
class BadgesSash < ActiveRecord::Base
|
3
|
-
include
|
3
|
+
include Merit::Models::BadgesSashConcern
|
4
4
|
|
5
5
|
has_many :activity_logs,
|
6
6
|
class_name: 'Merit::ActivityLog',
|
7
7
|
as: :related_change
|
8
8
|
|
9
9
|
validates_presence_of :badge_id, :sash
|
10
|
-
|
11
|
-
attr_accessible :badge_id if show_attr_accessible?
|
12
10
|
end
|
13
11
|
end
|
12
|
+
|
13
|
+
class Merit::BadgesSash < Merit::Models::ActiveRecord::BadgesSash; end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Merit
|
1
|
+
module Merit::Models::ActiveRecord
|
2
2
|
# Sash is a container for reputation data for meritable models. It's an
|
3
3
|
# indirection between meritable models and badges and scores (one to one
|
4
4
|
# relationship).
|
@@ -6,7 +6,8 @@ module Merit
|
|
6
6
|
# It's existence make join models like badges_users and scores_users
|
7
7
|
# unnecessary. It should be transparent at the application.
|
8
8
|
class Sash < ActiveRecord::Base
|
9
|
-
include
|
9
|
+
include Merit::Models::SashConcern
|
10
|
+
|
10
11
|
has_many :badges_sashes, dependent: :destroy
|
11
12
|
has_many :scores, dependent: :destroy, class_name: 'Merit::Score'
|
12
13
|
|
@@ -27,3 +28,5 @@ module Merit
|
|
27
28
|
end
|
28
29
|
end
|
29
30
|
end
|
31
|
+
|
32
|
+
class Merit::Sash < Merit::Models::ActiveRecord::Sash; end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Merit
|
1
|
+
module Merit::Models::ActiveRecord
|
2
2
|
class Score < ActiveRecord::Base
|
3
3
|
self.table_name = :merit_scores
|
4
4
|
belongs_to :sash
|
@@ -20,3 +20,6 @@ module Merit
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
23
|
+
|
24
|
+
class Merit::Score < Merit::Models::ActiveRecord::Score; end
|
25
|
+
class Merit::Score::Point < Merit::Models::ActiveRecord::Score::Point; end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Merit::Models
|
2
|
+
module SashConcern
|
3
|
+
def badges
|
4
|
+
badge_ids.map { |id| Merit::Badge.find id }
|
5
|
+
end
|
6
|
+
|
7
|
+
def badge_ids
|
8
|
+
badges_sashes.map(&:badge_id)
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_badge(badge_id)
|
12
|
+
bs = Merit::BadgesSash.new(badge_id: badge_id.to_i)
|
13
|
+
badges_sashes << bs
|
14
|
+
bs
|
15
|
+
end
|
16
|
+
|
17
|
+
def rm_badge(badge_id)
|
18
|
+
badges_sashes.where(badge_id: badge_id.to_i).first.try(:destroy)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Retrieve the number of points from a category
|
22
|
+
# By default all points are summed up
|
23
|
+
# @param category [String] The category
|
24
|
+
# @return [Integer] The number of points
|
25
|
+
def points(options = {})
|
26
|
+
if (category = options[:category])
|
27
|
+
scores.where(category: category).first.try(:points) || 0
|
28
|
+
else
|
29
|
+
scores.reduce(0) { |sum, score| sum + score.points }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_points(num_points, options = {})
|
34
|
+
point = Merit::Score::Point.new
|
35
|
+
point.num_points = num_points
|
36
|
+
scores
|
37
|
+
.where(category: options[:category] || 'default')
|
38
|
+
.first_or_create
|
39
|
+
.score_points << point
|
40
|
+
point
|
41
|
+
end
|
42
|
+
|
43
|
+
def subtract_points(num_points, options = {})
|
44
|
+
add_points(-num_points, options)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def create_scores
|
50
|
+
scores << Merit::Score.create
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
File without changes
|
@@ -44,30 +44,15 @@ module Merit
|
|
44
44
|
private
|
45
45
|
|
46
46
|
def grant_when_applies(scoped_model, rule, level)
|
47
|
-
|
47
|
+
scoped_model.where("#{rule.level_name} < #{level}").each do |object|
|
48
48
|
next unless rule.applies?(object)
|
49
|
+
|
49
50
|
object.update_attribute rule.level_name, level
|
50
51
|
end
|
51
|
-
rescue
|
52
|
+
rescue ActiveRecord::StatementInvalid
|
52
53
|
str = "Error while granting rankings. Probably you need to add
|
53
54
|
#{rule.level_name} column to #{scoped_model.class.name}."
|
54
55
|
raise RankAttributeNotDefined, str
|
55
56
|
end
|
56
|
-
|
57
|
-
def rank_exception
|
58
|
-
if defined? ActiveRecord
|
59
|
-
ActiveRecord::StatementInvalid
|
60
|
-
else
|
61
|
-
Exception
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def scope_to_promote(scope, level_name, level)
|
66
|
-
if Merit.orm == :mongoid
|
67
|
-
scope.where(:"#{level_name}".lt => level)
|
68
|
-
else
|
69
|
-
scope.where("#{level_name} < #{level}")
|
70
|
-
end
|
71
|
-
end
|
72
57
|
end
|
73
58
|
end
|
data/merit.gemspec
CHANGED
@@ -6,17 +6,19 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.files = `git ls-files`.split("\n").reject{|f| f =~ /^\./ }
|
7
7
|
s.test_files = `git ls-files -- test/*`.split("\n")
|
8
8
|
s.license = 'MIT'
|
9
|
-
s.version = '
|
9
|
+
s.version = '4.0.0'
|
10
10
|
s.authors = ["Tute Costa"]
|
11
11
|
s.email = 'tutecosta@gmail.com'
|
12
12
|
|
13
|
-
s.required_ruby_version = '>=
|
13
|
+
s.required_ruby_version = '>= 2.3.0'
|
14
14
|
|
15
|
-
s.
|
16
|
-
s.
|
15
|
+
s.add_runtime_dependency 'ambry', '~> 1.0.0'
|
16
|
+
s.add_runtime_dependency 'zeitwerk'
|
17
|
+
|
18
|
+
s.add_development_dependency 'rails', '>= 5.1.6'
|
17
19
|
s.add_development_dependency 'capybara'
|
18
20
|
s.add_development_dependency 'simplecov'
|
19
21
|
s.add_development_dependency 'rubocop'
|
20
22
|
s.add_development_dependency 'minitest-rails'
|
21
|
-
s.add_development_dependency 'mocha'
|
23
|
+
s.add_development_dependency 'mocha'
|
22
24
|
end
|