polo 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 241a2fd317d2b766497c31f824c4a9c76309df49
4
- data.tar.gz: cdfa23f93211a11f43414aba198b9edcf9e6203a
3
+ metadata.gz: d3f754e19121b0fb417f692c5ee333daeb8de049
4
+ data.tar.gz: 326da5077810478da02f66de52e749cac05866cc
5
5
  SHA512:
6
- metadata.gz: 63c36ebd40006d1f542474e86f4f91d343b1b99ab6b59054597f749274b3bdc919ea9ea2a5db8bfac2eafe46123030b55084ce2039767907b68555867acc3585
7
- data.tar.gz: 4765c393aa6e1b19b784bcbc8d14dc22e3fcab1f8a7a048bb1dfdf01e3f269290a51957f271aead96e1fbedf24de87aab70949dd14018a010aa451932a97e4d6
6
+ metadata.gz: 453c79f229642062534266178aabc162bbfdf06231c2b0237c828ef9277cc96c9987a9471096664a06c16b313f058c95f68e194bdd824a79ec01f232ad3a55f1
7
+ data.tar.gz: bfa5e063eb14430036621742fb3bc72e5159cf307a3efbd2e09894fb93c95c5face35766e8e78a7496ae9d2c7f05349796c021cd5452319271af0a688ea2a5a5
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ /gemfiles/*.gemfile.lock
data/.rspec CHANGED
File without changes
@@ -1 +1 @@
1
- 2.1.5
1
+ 2.2.1
@@ -6,4 +6,4 @@ gemfile:
6
6
  - gemfiles/rails40.gemfile
7
7
  - gemfiles/rails41.gemfile
8
8
  - gemfiles/rails42.gemfile
9
- before_install: gem install bundler -v 1.10.6
9
+ before_install: gem install bundler -v 1.11.2
data/Appraisals CHANGED
File without changes
@@ -1,3 +1,22 @@
1
+ ## 0.3.0
2
+
3
+ ### Breaking Changes
4
+
5
+ - None
6
+
7
+ ### Added
8
+
9
+ - [#30](https://github.com/IFTTT/polo/pull/30) Advanced obfuscation
10
+ - [#37](https://github.com/IFTTT/polo/pull/37) Custom adapters for Postgres and MySQL
11
+
12
+ ### Fixed
13
+
14
+ - [#26](https://github.com/IFTTT/polo/pull/26) Postgres - Use ActiveRecord methods to generate INSERT SQLs
15
+ - [#25](https://github.com/IFTTT/polo/pull/25) Fix custom strategies bug
16
+ - [#28](https://github.com/IFTTT/polo/pull/28) Only obfuscate fields when they are present
17
+ - [#35](https://github.com/IFTTT/polo/pull/35) Better support for Rails 4.0
18
+ - [#31](https://github.com/IFTTT/polo/pull/31) Fix link to Code of Conduct
19
+
1
20
  ## 0.2.0
2
21
 
3
22
  ### Breaking Changes
File without changes
data/Gemfile CHANGED
File without changes
File without changes
data/README.md CHANGED
@@ -10,7 +10,7 @@ Polo takes an `ActiveRecord::Base` seed object and traverses every whitelisted `
10
10
 
11
11
  You can then save those SQL `INSERTS` to .sql file and import the data to your favorite environment.
12
12
 
13
- # Motivation
13
+ ## Motivation
14
14
  Read our [blog post](https://medium.com/engineering-at-ifttt/happier-rails-development-with-polo-9df6819136d3#.f8ll3azeq) or check out this [presentation](https://speakerdeck.com/nettofarah/polo-working-with-real-world-data-in-development).
15
15
 
16
16
  ## Usage
@@ -137,14 +137,26 @@ Warning: This is not a security feature. Fields can still easily be rearranged b
137
137
 
138
138
  #### Advanced Obfuscation
139
139
 
140
- For more advanced obfuscation, you can pass in a custom obfuscation strategy.
141
- Polo will take in a lambda that can be used to transform sensitive data.
140
+ For more advanced obfuscation, you can pass in a custom obfuscation strategy. Polo will take in a lambda that can be used to transform sensitive data.
141
+
142
+ Using a `:symbol` as an obfuscate key targets all columns of that name. Passing an SQL selector as a `String` will target columns within the specified table.
142
143
 
143
144
  ````ruby
144
145
  Polo.configure do
145
- email_strategy = lambda {|e| "#{e.split("@")[0]}_test@example.com" }
146
- credit_card_strategy = lambda {|_| "4111111111111111"}
147
- obfuscate({email: email_strategy, credit_card: credit_card_strategy})
146
+
147
+ email_strategy = lambda do |email|
148
+ first_part = email.split("@")[0]
149
+ "#{first_part}@test.com"
150
+ end
151
+
152
+ credit_card_strategy = lambda do |credit_card|
153
+ "4123 4567 8910 1112"
154
+ end
155
+
156
+ obfuscate({
157
+ 'chefs.email' => email_strategy, # This only applies to the "email" column in the "chefs" table
158
+ :credit_card => credit_card_strategy # This applies to any column named "credit_card" across every table
159
+ })
148
160
  end
149
161
 
150
162
  Polo::Traveler.explore(AR::Chef, 1)
@@ -174,7 +186,7 @@ $ gem install polo
174
186
 
175
187
  ## Contributing
176
188
 
177
- Bug reports and pull requests are welcome on GitHub at https://github.com/IFTTT/polo. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
189
+ Bug reports and pull requests are welcome on GitHub at https://github.com/IFTTT/polo. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Code of Conduct](https://github.com/IFTTT/polo/blob/master/CODE_OF_CONDUCT.md).
178
190
 
179
191
  To run the specs across all supported version of Rails, check out the repo and
180
192
  follow these steps:
data/Rakefile CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,24 @@
1
+ module Polo
2
+ module Adapters
3
+ class MySQL
4
+ def on_duplicate_key_update(inserts, records)
5
+ insert_and_record = inserts.zip(records)
6
+ insert_and_record.map do |insert, record|
7
+ values_syntax = record.attributes.keys.map do |key|
8
+ "#{key} = VALUES(#{key})"
9
+ end
10
+
11
+ on_dup_syntax = "ON DUPLICATE KEY UPDATE #{values_syntax.join(', ')}"
12
+
13
+ "#{insert} #{on_dup_syntax}"
14
+ end
15
+ end
16
+
17
+ def ignore_transform(inserts, records)
18
+ inserts.map do |insert|
19
+ insert.gsub("INSERT", "INSERT IGNORE")
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,32 @@
1
+ module Polo
2
+ module Adapters
3
+ class Postgres
4
+ # TODO: Implement UPSERT. This command became available in 9.1.
5
+ #
6
+ # See: http://www.the-art-of-web.com/sql/upsert/
7
+ def on_duplicate_key_update(inserts, records)
8
+ raise 'on_duplicate: :override is not currently supported in the PostgreSQL adapter'
9
+ end
10
+
11
+ # Internal: Transforms an INSERT with PostgreSQL-specific syntax. Ignores
12
+ # records that alread exist in the table. To do this, it uses
13
+ # a heuristic, i.e. checks if there is a record with the same id
14
+ # in the table.
15
+ # See: http://stackoverflow.com/a/6527838/32816
16
+ #
17
+ # inserts - The Array of INSERT statements.
18
+ # records - The Array of Arel objects.
19
+ #
20
+ # Returns the Array of transformed INSERT statements.
21
+ def ignore_transform(inserts, records)
22
+ insert_and_record = inserts.zip(records)
23
+ insert_and_record.map do |insert, record|
24
+ table_name = record.class.arel_table.name
25
+ id = record[:id]
26
+ insert = insert.gsub(/VALUES \((.+)\)$/m, 'SELECT \\1')
27
+ insert << " WHERE NOT EXISTS (SELECT 1 FROM #{table_name} WHERE id=#{id});"
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
File without changes
@@ -1,10 +1,11 @@
1
1
  module Polo
2
2
 
3
3
  class Configuration
4
- attr_reader :on_duplicate_strategy, :blacklist
4
+ attr_reader :on_duplicate_strategy, :blacklist, :adapter
5
5
 
6
6
  def initialize(options={})
7
- options = { on_duplicate: nil, obfuscate: {} }.merge(options)
7
+ options = { on_duplicate: nil, obfuscate: {}, adapter: :mysql }.merge(options)
8
+ @adapter = options[:adapter]
8
9
  @on_duplicate_strategy = options[:on_duplicate]
9
10
  obfuscate(options[:obfuscate])
10
11
  end
@@ -33,5 +34,9 @@ module Polo
33
34
  def on_duplicate(strategy)
34
35
  @on_duplicate_strategy = strategy
35
36
  end
37
+
38
+ def set_adapter(db)
39
+ @adapter = db
40
+ end
36
41
  end
37
42
  end
@@ -1,93 +1,89 @@
1
1
  require 'active_record'
2
2
  require 'polo/configuration'
3
+ require 'polo/adapters/mysql'
4
+ require 'polo/adapters/postgres'
3
5
 
4
6
  module Polo
5
7
  class SqlTranslator
6
8
 
7
- def initialize(object, configuration=Configuration.new)
9
+ def initialize(object, configuration = Configuration.new)
8
10
  @record = object
9
11
  @configuration = configuration
10
- end
11
-
12
- def to_sql
13
- records = Array.wrap(@record)
14
12
 
15
- sqls = records.map do |record|
16
- raw_sql(record)
13
+ case @configuration.adapter
14
+ when :mysql
15
+ @adapter = Polo::Adapters::MySQL.new
16
+ when :postgres
17
+ @adapter = Polo::Adapters::Postgres.new
18
+ else
19
+ raise "Unknown SQL adapter: #{@configuration.adapter}"
17
20
  end
18
-
19
- if @configuration.on_duplicate_strategy == :ignore
20
- sqls = ignore_transform(sqls)
21
- end
22
-
23
- if @configuration.on_duplicate_strategy == :override
24
- sqls = on_duplicate_key_update(sqls, records)
25
- end
26
-
27
- sqls
28
21
  end
29
22
 
30
- private
31
-
32
- def on_duplicate_key_update(sqls, records)
33
- insert_and_record = sqls.zip(records)
34
- insert_and_record.map do |insert, record|
35
- values_syntax = record.attributes.keys.map do |key|
36
- "#{key} = VALUES(#{key})"
37
- end
38
-
39
- on_dup_syntax = "ON DUPLICATE KEY UPDATE #{values_syntax.join(', ')}"
40
-
41
- "#{insert} #{on_dup_syntax}"
23
+ def to_sql
24
+ case @configuration.on_duplicate_strategy
25
+ when :ignore
26
+ @adapter.ignore_transform(inserts, records)
27
+ when :override
28
+ @adapter.on_duplicate_key_update(inserts, records)
29
+ else inserts
42
30
  end
43
31
  end
44
32
 
45
- def ignore_transform(inserts)
46
- inserts.map do |insert|
47
- insert.gsub("INSERT", "INSERT IGNORE")
48
- end
33
+ def records
34
+ Array.wrap(@record)
49
35
  end
50
36
 
51
- def raw_sql(record)
52
- connection = ActiveRecord::Base.connection
53
- attributes = record.attributes
54
-
55
- keys = attributes.keys.map do |key|
56
- "`#{key}`"
37
+ def inserts
38
+ records.map do |record|
39
+ raw_sql(record)
57
40
  end
41
+ end
58
42
 
59
- values = attributes.map do |key, value|
60
- column = record.column_for_attribute(key)
61
- connection.quote(cast_attribute(record, column, value))
62
- end
43
+ private
63
44
 
64
- "INSERT INTO `#{record.class.table_name}` (#{keys.join(', ')}) VALUES (#{values.join(', ')})"
45
+ # Internal: Generates an insert SQL statement for a given record
46
+ #
47
+ # It will make use of the InsertManager class from the Arel gem to generate
48
+ # insert statements
49
+ #
50
+ def raw_sql(record)
51
+ record.class.arel_table.create_insert.tap do |insert_manager|
52
+ insert_manager.insert(insert_values(record))
53
+ end.to_sql
65
54
  end
66
55
 
67
- module ActiveRecordLessThanFourPointTwo
68
- def cast_attribute(record, column, value)
69
- attribute = record.send(:type_cast_attribute_for_write, column, value)
70
-
71
- if record.class.serialized_attributes.include?(column.name)
72
- attribute.serialize
73
- else
74
- attribute
75
- end
56
+ # Internal: Returns an object's attribute definitions along with
57
+ # their set values (for Rails 3.x).
58
+ #
59
+ module ActiveRecordLessThanFour
60
+ def insert_values(record)
61
+ record.send(:arel_attributes_values)
76
62
  end
77
63
  end
78
64
 
79
- module ActiveRecordFourPointTwoOrGreater
80
- def cast_attribute(record, column, value)
81
- column.type_cast_for_database(value)
65
+ # Internal: Returns an object's attribute definitions along with
66
+ # their set values (for Rails >= 4.x).
67
+ #
68
+ # From Rails 4.2 onwards, for some reason attributes with custom serializers
69
+ # wouldn't be properly serialized automatically. That's why explict
70
+ # 'type_cast' call are necessary.
71
+ #
72
+ module ActiveRecordFourOrGreater
73
+ def insert_values(record)
74
+ connection = ActiveRecord::Base.connection
75
+ values = record.send(:arel_attributes_with_values_for_create, record.attribute_names)
76
+ values.each do |attribute, value|
77
+ column = record.send(:column_for_attribute, attribute.name)
78
+ values[attribute] = connection.type_cast(value, column)
79
+ end
82
80
  end
83
81
  end
84
82
 
85
- if ActiveRecord::VERSION::STRING.start_with?('3.2') ||
86
- ActiveRecord::VERSION::STRING.start_with?('4.0') ||
87
- ActiveRecord::VERSION::STRING.start_with?('4.1')
88
- include ActiveRecordLessThanFourPointTwo
83
+ if ActiveRecord::VERSION::MAJOR < 4
84
+ include ActiveRecordLessThanFour
89
85
  else
90
- include ActiveRecordFourPointTwoOrGreater
86
+ include ActiveRecordFourOrGreater
91
87
  end
92
88
  end
93
89
  end
@@ -38,14 +38,31 @@ module Polo
38
38
  next if intersection(instance.attributes.keys, fields).empty?
39
39
 
40
40
  fields.each do |field, strategy|
41
- value = instance.attributes[field.to_s] || ''
42
- instance.send("#{field}=", new_field_value(field, strategy, value))
41
+ field = field.to_s
42
+
43
+ if table = table_name(field)
44
+ field = field_name(field)
45
+ end
46
+
47
+ correct_table = table.nil? || instance.class.table_name == table
48
+
49
+ if correct_table && value = instance.attributes[field]
50
+ instance.send("#{field}=", new_field_value(field, strategy, value))
51
+ end
43
52
  end
44
53
  end
45
54
  end
46
55
 
56
+ def field_name(field)
57
+ field.to_s.include?('.') ? field.split('.').last : field.to_s
58
+ end
59
+
60
+ def table_name(field)
61
+ field.to_s.include?('.') ? field.split('.').first : nil
62
+ end
63
+
47
64
  def intersection(attrs, fields)
48
- attrs & fields.keys.map(&:to_s)
65
+ attrs & fields.map { |pair| field_name(pair.first) }
49
66
  end
50
67
 
51
68
  def new_field_value(field, strategy, value)
@@ -1,3 +1,3 @@
1
1
  module Polo
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
File without changes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Netto Farah
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-12-04 00:00:00.000000000 Z
11
+ date: 2016-04-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -114,14 +114,12 @@ files:
114
114
  - README.md
115
115
  - Rakefile
116
116
  - gemfiles/rails32.gemfile
117
- - gemfiles/rails32.gemfile.lock
118
117
  - gemfiles/rails40.gemfile
119
- - gemfiles/rails40.gemfile.lock
120
118
  - gemfiles/rails41.gemfile
121
- - gemfiles/rails41.gemfile.lock
122
119
  - gemfiles/rails42.gemfile
123
- - gemfiles/rails42.gemfile.lock
124
120
  - lib/polo.rb
121
+ - lib/polo/adapters/mysql.rb
122
+ - lib/polo/adapters/postgres.rb
125
123
  - lib/polo/collector.rb
126
124
  - lib/polo/configuration.rb
127
125
  - lib/polo/sql_translator.rb
@@ -1,61 +0,0 @@
1
- PATH
2
- remote: ../
3
- specs:
4
- polo (0.1.0)
5
- activerecord (>= 3.2)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- activemodel (3.2.22)
11
- activesupport (= 3.2.22)
12
- builder (~> 3.0.0)
13
- activerecord (3.2.22)
14
- activemodel (= 3.2.22)
15
- activesupport (= 3.2.22)
16
- arel (~> 3.0.2)
17
- tzinfo (~> 0.3.29)
18
- activesupport (3.2.22)
19
- i18n (~> 0.6, >= 0.6.4)
20
- multi_json (~> 1.0)
21
- appraisal (2.1.0)
22
- bundler
23
- rake
24
- thor (>= 0.14.0)
25
- arel (3.0.3)
26
- builder (3.0.4)
27
- diff-lcs (1.2.5)
28
- i18n (0.7.0)
29
- multi_json (1.11.2)
30
- rake (10.4.2)
31
- rspec (3.3.0)
32
- rspec-core (~> 3.3.0)
33
- rspec-expectations (~> 3.3.0)
34
- rspec-mocks (~> 3.3.0)
35
- rspec-core (3.3.2)
36
- rspec-support (~> 3.3.0)
37
- rspec-expectations (3.3.1)
38
- diff-lcs (>= 1.2.0, < 2.0)
39
- rspec-support (~> 3.3.0)
40
- rspec-mocks (3.3.2)
41
- diff-lcs (>= 1.2.0, < 2.0)
42
- rspec-support (~> 3.3.0)
43
- rspec-support (3.3.0)
44
- sqlite3 (1.3.10)
45
- thor (0.19.1)
46
- tzinfo (0.3.44)
47
-
48
- PLATFORMS
49
- ruby
50
-
51
- DEPENDENCIES
52
- activerecord (= 3.2.22)
53
- appraisal
54
- bundler (~> 1.10)
55
- polo!
56
- rake (~> 10.0)
57
- rspec
58
- sqlite3 (= 1.3.10)
59
-
60
- BUNDLED WITH
61
- 1.10.6
@@ -1,67 +0,0 @@
1
- PATH
2
- remote: ../
3
- specs:
4
- polo (0.1.0)
5
- activerecord (>= 3.2)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- activemodel (4.0.13)
11
- activesupport (= 4.0.13)
12
- builder (~> 3.1.0)
13
- activerecord (4.0.13)
14
- activemodel (= 4.0.13)
15
- activerecord-deprecated_finders (~> 1.0.2)
16
- activesupport (= 4.0.13)
17
- arel (~> 4.0.0)
18
- activerecord-deprecated_finders (1.0.4)
19
- activesupport (4.0.13)
20
- i18n (~> 0.6, >= 0.6.9)
21
- minitest (~> 4.2)
22
- multi_json (~> 1.3)
23
- thread_safe (~> 0.1)
24
- tzinfo (~> 0.3.37)
25
- appraisal (2.1.0)
26
- bundler
27
- rake
28
- thor (>= 0.14.0)
29
- arel (4.0.2)
30
- builder (3.1.4)
31
- diff-lcs (1.2.5)
32
- i18n (0.7.0)
33
- minitest (4.7.5)
34
- multi_json (1.11.2)
35
- rake (10.4.2)
36
- rspec (3.3.0)
37
- rspec-core (~> 3.3.0)
38
- rspec-expectations (~> 3.3.0)
39
- rspec-mocks (~> 3.3.0)
40
- rspec-core (3.3.2)
41
- rspec-support (~> 3.3.0)
42
- rspec-expectations (3.3.1)
43
- diff-lcs (>= 1.2.0, < 2.0)
44
- rspec-support (~> 3.3.0)
45
- rspec-mocks (3.3.2)
46
- diff-lcs (>= 1.2.0, < 2.0)
47
- rspec-support (~> 3.3.0)
48
- rspec-support (3.3.0)
49
- sqlite3 (1.3.10)
50
- thor (0.19.1)
51
- thread_safe (0.3.5)
52
- tzinfo (0.3.44)
53
-
54
- PLATFORMS
55
- ruby
56
-
57
- DEPENDENCIES
58
- activerecord (= 4.0.13)
59
- appraisal
60
- bundler (~> 1.10)
61
- polo!
62
- rake (~> 10.0)
63
- rspec
64
- sqlite3 (= 1.3.10)
65
-
66
- BUNDLED WITH
67
- 1.10.6
@@ -1,66 +0,0 @@
1
- PATH
2
- remote: ../
3
- specs:
4
- polo (0.1.0)
5
- activerecord (>= 3.2)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- activemodel (4.1.12)
11
- activesupport (= 4.1.12)
12
- builder (~> 3.1)
13
- activerecord (4.1.12)
14
- activemodel (= 4.1.12)
15
- activesupport (= 4.1.12)
16
- arel (~> 5.0.0)
17
- activesupport (4.1.12)
18
- i18n (~> 0.6, >= 0.6.9)
19
- json (~> 1.7, >= 1.7.7)
20
- minitest (~> 5.1)
21
- thread_safe (~> 0.1)
22
- tzinfo (~> 1.1)
23
- appraisal (2.1.0)
24
- bundler
25
- rake
26
- thor (>= 0.14.0)
27
- arel (5.0.1.20140414130214)
28
- builder (3.2.2)
29
- diff-lcs (1.2.5)
30
- i18n (0.7.0)
31
- json (1.8.3)
32
- minitest (5.8.0)
33
- rake (10.4.2)
34
- rspec (3.3.0)
35
- rspec-core (~> 3.3.0)
36
- rspec-expectations (~> 3.3.0)
37
- rspec-mocks (~> 3.3.0)
38
- rspec-core (3.3.2)
39
- rspec-support (~> 3.3.0)
40
- rspec-expectations (3.3.1)
41
- diff-lcs (>= 1.2.0, < 2.0)
42
- rspec-support (~> 3.3.0)
43
- rspec-mocks (3.3.2)
44
- diff-lcs (>= 1.2.0, < 2.0)
45
- rspec-support (~> 3.3.0)
46
- rspec-support (3.3.0)
47
- sqlite3 (1.3.10)
48
- thor (0.19.1)
49
- thread_safe (0.3.5)
50
- tzinfo (1.2.2)
51
- thread_safe (~> 0.1)
52
-
53
- PLATFORMS
54
- ruby
55
-
56
- DEPENDENCIES
57
- activerecord (= 4.1.12)
58
- appraisal
59
- bundler (~> 1.10)
60
- polo!
61
- rake (~> 10.0)
62
- rspec
63
- sqlite3 (= 1.3.10)
64
-
65
- BUNDLED WITH
66
- 1.10.6
@@ -1,66 +0,0 @@
1
- PATH
2
- remote: ../
3
- specs:
4
- polo (0.1.0)
5
- activerecord (>= 3.2)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- activemodel (4.2.3)
11
- activesupport (= 4.2.3)
12
- builder (~> 3.1)
13
- activerecord (4.2.3)
14
- activemodel (= 4.2.3)
15
- activesupport (= 4.2.3)
16
- arel (~> 6.0)
17
- activesupport (4.2.3)
18
- i18n (~> 0.7)
19
- json (~> 1.7, >= 1.7.7)
20
- minitest (~> 5.1)
21
- thread_safe (~> 0.3, >= 0.3.4)
22
- tzinfo (~> 1.1)
23
- appraisal (2.1.0)
24
- bundler
25
- rake
26
- thor (>= 0.14.0)
27
- arel (6.0.3)
28
- builder (3.2.2)
29
- diff-lcs (1.2.5)
30
- i18n (0.7.0)
31
- json (1.8.3)
32
- minitest (5.8.0)
33
- rake (10.4.2)
34
- rspec (3.3.0)
35
- rspec-core (~> 3.3.0)
36
- rspec-expectations (~> 3.3.0)
37
- rspec-mocks (~> 3.3.0)
38
- rspec-core (3.3.2)
39
- rspec-support (~> 3.3.0)
40
- rspec-expectations (3.3.1)
41
- diff-lcs (>= 1.2.0, < 2.0)
42
- rspec-support (~> 3.3.0)
43
- rspec-mocks (3.3.2)
44
- diff-lcs (>= 1.2.0, < 2.0)
45
- rspec-support (~> 3.3.0)
46
- rspec-support (3.3.0)
47
- sqlite3 (1.3.10)
48
- thor (0.19.1)
49
- thread_safe (0.3.5)
50
- tzinfo (1.2.2)
51
- thread_safe (~> 0.1)
52
-
53
- PLATFORMS
54
- ruby
55
-
56
- DEPENDENCIES
57
- activerecord (= 4.2.3)
58
- appraisal
59
- bundler (~> 1.10)
60
- polo!
61
- rake (~> 10.0)
62
- rspec
63
- sqlite3 (= 1.3.10)
64
-
65
- BUNDLED WITH
66
- 1.10.6