voight_kampff 0.2.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -4
  3. data/README.md +75 -0
  4. data/config.ru +7 -0
  5. data/config/crawler-user-agents.json +750 -0
  6. data/lib/tasks/voight_kampff.rake +9 -7
  7. data/lib/voight_kampff.rb +3 -29
  8. data/lib/voight_kampff/engine.rb +0 -5
  9. data/lib/voight_kampff/rack_request.rb +11 -0
  10. data/lib/voight_kampff/test.rb +18 -59
  11. data/lib/voight_kampff/version.rb +1 -1
  12. data/spec/controllers/replicants_controller_spec.rb +31 -0
  13. data/spec/internal/app/controllers/replicants_controller.rb +13 -0
  14. data/spec/internal/config/routes.rb +4 -0
  15. data/spec/internal/log/.gitignore +1 -0
  16. data/{tests/test_app → spec/internal}/public/favicon.ico +0 -0
  17. data/spec/lib/voight_kampff/rack_request_spec.rb +33 -0
  18. data/spec/lib/voight_kampff/test_spec.rb +28 -0
  19. data/spec/lib/voight_kampff_spec.rb +27 -0
  20. data/spec/spec_helper.rb +11 -0
  21. data/spec/support/humans.rb +9 -0
  22. data/spec/support/replicants.rb +5 -0
  23. data/voight_kampff.gemspec +4 -5
  24. metadata +30 -70
  25. data/.autotest +0 -22
  26. data/CHANGELOG.rdoc +0 -16
  27. data/README.markdown +0 -63
  28. data/Rakefile +0 -20
  29. data/config/initializers/extend_action_dispatch_request.rb +0 -46
  30. data/config/user_agents.yml +0 -12438
  31. data/lib/voight_kampff/base.rb +0 -7
  32. data/lib/voight_kampff/user_agents_parser.rb +0 -54
  33. data/tests/spec/minitest_helper.rb +0 -2
  34. data/tests/spec/voight_kampff_spec.rb +0 -10
  35. data/tests/test_app/.gitignore +0 -15
  36. data/tests/test_app/Gemfile +0 -39
  37. data/tests/test_app/Rakefile +0 -7
  38. data/tests/test_app/app/controllers/application_controller.rb +0 -3
  39. data/tests/test_app/app/helpers/application_helper.rb +0 -2
  40. data/tests/test_app/app/mailers/.gitkeep +0 -0
  41. data/tests/test_app/app/models/.gitkeep +0 -0
  42. data/tests/test_app/app/views/layouts/application.html.erb +0 -14
  43. data/tests/test_app/config.ru +0 -4
  44. data/tests/test_app/config/application.rb +0 -62
  45. data/tests/test_app/config/boot.rb +0 -6
  46. data/tests/test_app/config/database.yml +0 -25
  47. data/tests/test_app/config/environment.rb +0 -5
  48. data/tests/test_app/config/environments/development.rb +0 -37
  49. data/tests/test_app/config/environments/production.rb +0 -67
  50. data/tests/test_app/config/environments/test.rb +0 -37
  51. data/tests/test_app/config/initializers/backtrace_silencers.rb +0 -7
  52. data/tests/test_app/config/initializers/inflections.rb +0 -15
  53. data/tests/test_app/config/initializers/mime_types.rb +0 -5
  54. data/tests/test_app/config/initializers/secret_token.rb +0 -7
  55. data/tests/test_app/config/initializers/session_store.rb +0 -8
  56. data/tests/test_app/config/initializers/wrap_parameters.rb +0 -14
  57. data/tests/test_app/config/locales/en.yml +0 -5
  58. data/tests/test_app/config/routes.rb +0 -58
  59. data/tests/test_app/lib/assets/.gitkeep +0 -0
  60. data/tests/test_app/lib/tasks/.gitkeep +0 -0
  61. data/tests/test_app/log/.gitkeep +0 -0
  62. data/tests/test_app/public/404.html +0 -26
  63. data/tests/test_app/public/422.html +0 -26
  64. data/tests/test_app/public/500.html +0 -25
  65. data/tests/test_app/public/index.html +0 -241
  66. data/tests/test_app/public/robots.txt +0 -5
  67. data/tests/test_app/script/rails +0 -6
  68. data/tests/test_app/test/fixtures/.gitkeep +0 -0
  69. data/tests/test_app/test/functional/.gitkeep +0 -0
  70. data/tests/test_app/test/integration/.gitkeep +0 -0
  71. data/tests/test_app/test/performance/browsing_test.rb +0 -12
  72. data/tests/test_app/test/test_helper.rb +0 -13
  73. data/tests/test_app/test/unit/.gitkeep +0 -0
  74. data/tests/test_app/vendor/assets/javascripts/.gitkeep +0 -0
  75. data/tests/test_app/vendor/assets/stylesheets/.gitkeep +0 -0
  76. data/tests/test_app/vendor/plugins/.gitkeep +0 -0
@@ -1,12 +1,14 @@
1
1
  namespace :voight_kampff do
2
-
3
- desc 'Import a new uesr_agents.yml file'
2
+ desc 'Import a new crawler-user-agents.json file'
4
3
  task :import_user_agents, :url do |t, args|
5
- args.with_defaults :url => 'http://www.user-agents.org/allagents.xml'
6
- agents = VoightKampff::UserAgentsParser.new(args[:url])
4
+ args.with_defaults url: 'https://raw.githubusercontent.com/monperrus/crawler-user-agents/master/crawler-user-agents.json'
7
5
 
8
- file = File.open(Rails.root.join('config','user_agents.yml'), 'w')
9
- file.write(agents.to_yaml)
10
- end
6
+ require 'net/http'
11
7
 
8
+ uri = URI(args[:url])
9
+ contents = Net::HTTP.get(uri)
10
+
11
+ file = File.open('./config/crawler-user-agents.json', 'w')
12
+ file.write(contents)
13
+ end
12
14
  end
data/lib/voight_kampff.rb CHANGED
@@ -1,11 +1,11 @@
1
+ require 'json'
2
+
1
3
  require 'voight_kampff/test'
2
- require 'voight_kampff/user_agents_parser'
4
+ require 'voight_kampff/rack_request'
3
5
  require 'voight_kampff/engine' if defined?(Rails)
4
6
 
5
7
  module VoightKampff
6
-
7
8
  class << self
8
-
9
9
  def root
10
10
  require 'pathname'
11
11
  Pathname.new File.expand_path '..', File.dirname(__FILE__)
@@ -20,36 +20,10 @@ module VoightKampff
20
20
  end
21
21
  alias :replicant? :bot?
22
22
 
23
- def browser?(user_agent_string)
24
- test(user_agent_string).browser?
25
- end
26
-
27
- def checker?(user_agent_string)
28
- test(user_agent_string).checker?
29
- end
30
-
31
- def downloader?(user_agent_string)
32
- test(user_agent_string).downloader?
33
- end
34
-
35
- def proxy?(user_agent_string)
36
- test(user_agent_string).proxy?
37
- end
38
-
39
- def crawler?(user_agent_string)
40
- test(user_agent_string).crawler?
41
- end
42
-
43
- def spam?(user_agent_string)
44
- test(user_agent_string).spam?
45
- end
46
-
47
23
  private
48
24
 
49
25
  def test(user_agent_string)
50
26
  VoightKampff::Test.new(user_agent_string)
51
27
  end
52
-
53
28
  end
54
-
55
29
  end
@@ -1,12 +1,7 @@
1
- require 'voight_kampff'
2
- require 'rails'
3
-
4
1
  module VoightKampff
5
2
  class Engine < Rails::Engine
6
-
7
3
  rake_tasks do
8
4
  load 'tasks/voight_kampff.rake'
9
5
  end
10
-
11
6
  end
12
7
  end
@@ -0,0 +1,11 @@
1
+ # Reopen the Rack::Request class to add bot detection methods
2
+ class Rack::Request
3
+ def human?
4
+ VoightKampff::Test.new(user_agent).human?
5
+ end
6
+
7
+ def bot?
8
+ VoightKampff::Test.new(user_agent).bot?
9
+ end
10
+ alias :replicant? :bot?
11
+ end
@@ -1,88 +1,47 @@
1
1
  module VoightKampff
2
-
3
2
  class Test
3
+ CRAWLERS_FILENAME = 'crawler-user-agents.json'
4
4
 
5
5
  attr_accessor :user_agent_string
6
- attr_accessor :types
7
6
 
8
7
  def initialize(user_agent_string)
9
- load_agents
10
8
  @user_agent_string = user_agent_string
11
- @types = Array(agent['types']).map(&:to_sym)
12
- @description = agent['description']
13
9
  end
14
10
 
15
11
  def agent
16
- @agent ||= @@agents.find do |agent|
17
- if agent['string_match'] == 'regex'
18
- @user_agent_string =~ Regexp.new(agent['string'], Regexp::IGNORECASE)
19
- else
20
- @user_agent_string.to_s.casecmp(agent['string'].to_s) == 0
21
- end
22
- end || {}
23
- end
12
+ load_crawlers
24
13
 
25
- def has_type?(*types)
26
- return nil if agent.empty?
27
-
28
- types.any? do |type|
29
- @types.include? type
30
- end
14
+ @agent ||= @@crawlers.find do |crawler|
15
+ user_agent_string =~ Regexp.new(crawler['pattern'], Regexp::IGNORECASE)
16
+ end || {}
31
17
  end
32
18
 
33
19
  def human?
34
- has_type? :browser, :downloader, :proxy
20
+ agent.empty?
35
21
  end
36
22
 
37
23
  def bot?
38
- has_type? :checker, :crawler, :spam
24
+ !human?
39
25
  end
40
26
  alias :replicant? :bot?
41
27
 
42
- def browser?
43
- has_type? :browser
44
- end
45
-
46
- def checker?
47
- has_type? :checker
48
- end
49
-
50
- def downloader?
51
- has_type? :downloader
52
- end
28
+ private
53
29
 
54
- def proxy?
55
- has_type? :proxy
56
- end
30
+ def lookup_paths
31
+ # These paths should be orderd by priority
32
+ base_paths = []
33
+ base_paths << Rails.root if defined? Rails
34
+ base_paths << VoightKampff.root
57
35
 
58
- def crawler?
59
- has_type? :crawler
36
+ base_paths.map { |p| p.join('config', CRAWLERS_FILENAME) }
60
37
  end
61
38
 
62
- def spam?
63
- has_type? :spam
39
+ def preferred_path
40
+ lookup_paths.find { |path| File.exists? path }
64
41
  end
65
42
 
66
- private
67
-
68
- def load_agents
69
- @@agents ||= []
70
- if @@agents.empty?
71
-
72
- base_paths = []
73
- base_paths << Rails.root if defined? Rails
74
- base_paths << VoightKampff.root
75
- rel_path = ['config', 'user_agents.yml']
76
-
77
- base_paths.any? do |base_path|
78
- if File.exists? base_path.join(*rel_path)
79
- @@agents = YAML.load(File.open(base_path.join(*rel_path), 'r'))
80
- end
81
- end
82
-
83
- end
43
+ def load_crawlers
44
+ @@crawlers ||= JSON.load(File.open(preferred_path, 'r'))
84
45
  end
85
-
86
46
  end
87
-
88
47
  end
@@ -1,3 +1,3 @@
1
1
  module VoightKampff
2
- VERSION = '0.2.2'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe ReplicantsController, type: :controller do
4
+ let(:user_agent_string) { '' }
5
+ before do
6
+ expect(request).to receive(:user_agent).and_return user_agent_string
7
+ get :index
8
+ end
9
+
10
+ HUMANS.each do |name, ua_string|
11
+ context "when user agent is #{name}" do
12
+ let(:user_agent_string) { ua_string }
13
+
14
+ it 'is forbidden' do
15
+ expect(response.status).to eql 403
16
+ expect(response.body).to match(/No replicants here/)
17
+ end
18
+ end
19
+ end
20
+
21
+ REPLICANTS.each do |name, ua_string|
22
+ context "when user agent is #{name}" do
23
+ let(:user_agent_string) { ua_string }
24
+
25
+ it 'is successful' do
26
+ expect(response.status).to eql 200
27
+ expect(response.body).to match(/Rick Deckard/)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ class ReplicantsController < ActionController::Base
2
+ def index
3
+ header = "Replicants:\n===========\n"
4
+
5
+ status, content = if request.bot?
6
+ [200, '- Rick Deckard']
7
+ else
8
+ [403, 'No replicants here']
9
+ end
10
+
11
+ render plain: header + content, status: status
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ Rails.application.routes.draw do
2
+ resources :replicants, only: :index
3
+ root to: 'replicants#index'
4
+ end
@@ -0,0 +1 @@
1
+ *.log
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::Request do
4
+ let(:user_agent_string) { }
5
+ let(:env) { {'HTTP_USER_AGENT' => user_agent_string} }
6
+ subject { Rack::Request.new(env) }
7
+
8
+ it { expect(subject).to respond_to :human? }
9
+ it { expect(subject).to respond_to :bot? }
10
+ it { expect(subject).to respond_to :replicant? }
11
+
12
+ HUMANS.each do |name, ua_string|
13
+ context "when user agent is #{name}" do
14
+ let(:user_agent_string) { ua_string }
15
+
16
+ it 'is not a replicant' do
17
+ expect(subject.human?).to eql true
18
+ expect(subject.bot?).to eql false
19
+ end
20
+ end
21
+ end
22
+
23
+ REPLICANTS.each do |name, ua_string|
24
+ context "when user agent is #{name}" do
25
+ let(:user_agent_string) { ua_string }
26
+
27
+ it 'is a replicant' do
28
+ expect(subject.bot?).to eql true
29
+ expect(subject.human?).to eql false
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe VoightKampff::Test do
4
+ let(:user_agent_string) { nil }
5
+ subject { VoightKampff::Test.new(user_agent_string) }
6
+
7
+ HUMANS.each do |name, ua_string|
8
+ context "when user agent is #{name}" do
9
+ let(:user_agent_string) { ua_string }
10
+
11
+ it 'is not a replicant' do
12
+ expect(subject.human?).to be true
13
+ expect(subject.bot?).to be false
14
+ end
15
+ end
16
+ end
17
+
18
+ REPLICANTS.each do |name, ua_string|
19
+ context "when user agent is #{name}" do
20
+ let(:user_agent_string) { ua_string }
21
+
22
+ it 'is a replicant' do
23
+ expect(subject.bot?).to be true
24
+ expect(subject.human?).to be false
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe VoightKampff do
4
+ subject { VoightKampff }
5
+
6
+ HUMANS.each do |name, ua_string|
7
+ context "when user agent is #{ua_string}" do
8
+ let(:user_agent_string) { ua_string }
9
+
10
+ it 'is not a replicant' do
11
+ expect(subject.human?(user_agent_string)).to be true
12
+ expect(subject.bot?(user_agent_string)).to be false
13
+ end
14
+ end
15
+ end
16
+
17
+ REPLICANTS.each do |name, ua_string|
18
+ context "when user agent is #{ua_string}" do
19
+ let(:user_agent_string) { ua_string }
20
+
21
+ it 'is a replicant' do
22
+ expect(subject.bot?(user_agent_string)).to be true
23
+ expect(subject.human?(user_agent_string)).to be false
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ require 'bundler/setup'
2
+ require 'combustion'
3
+ require 'voight_kampff'
4
+
5
+ Combustion.initialize! :action_controller
6
+
7
+ require 'rspec/rails'
8
+ Dir['./spec/support/**/*.rb'].each { |f| require f }
9
+
10
+ RSpec.configure do |config|
11
+ end
@@ -0,0 +1,9 @@
1
+ HUMANS = {
2
+ 'Unknown' => nil, # for the moment we're treating a blank user agent string as not a bot
3
+ 'Chrome' => 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
4
+ 'Firefox' => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1',
5
+ 'Safari' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/7046A194A',
6
+ 'Internet Explorer' => 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko',
7
+ 'Chrome Mobile' => 'Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19',
8
+ 'Safari for iOS' => 'Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53'
9
+ }
@@ -0,0 +1,5 @@
1
+ REPLICANTS = {
2
+ 'Googlebot' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
3
+ 'Bingbot' => 'Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)',
4
+ 'Yahoo! Slurp' => 'Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)'
5
+ }
@@ -21,10 +21,9 @@ Gem::Specification.new do |s|
21
21
  s.test_files = `git ls-files -- {tests}/**/*`.split("\n")
22
22
  s.require_path = 'lib'
23
23
 
24
- s.add_dependency 'httpclient', '~> 2.2'
24
+ s.add_dependency 'rack', '~> 1.6'
25
25
 
26
- # Nokogiri 1.6.0 has dropped support for Ruby 1.8.7
27
- s.add_dependency 'nokogiri', (RUBY_VERSION.match("1.8.7") ? '1.5.10' : '~> 1.6')
28
- s.add_development_dependency 'minitest', '~> 4.7'
29
- s.add_development_dependency 'rdoc', '~> 2.4'
26
+ s.add_development_dependency 'rails', '~> 4.2'
27
+ s.add_development_dependency 'rspec-rails', '~> 3.3'
28
+ s.add_development_dependency 'combustion', '~> 0.5'
30
29
  end
metadata CHANGED
@@ -1,141 +1,101 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: voight_kampff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Crownoble
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-05 00:00:00.000000000 Z
11
+ date: 2015-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: httpclient
14
+ name: rack
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.2'
19
+ version: '1.6'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.2'
26
+ version: '1.6'
27
27
  - !ruby/object:Gem::Dependency
28
- name: nokogiri
28
+ name: rails
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.6'
34
- type: :runtime
33
+ version: '4.2'
34
+ type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.6'
40
+ version: '4.2'
41
41
  - !ruby/object:Gem::Dependency
42
- name: minitest
42
+ name: rspec-rails
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '4.7'
47
+ version: '3.3'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '4.7'
54
+ version: '3.3'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rdoc
56
+ name: combustion
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '2.4'
61
+ version: '0.5'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '2.4'
68
+ version: '0.5'
69
69
  description: Voight-Kampff detects bots, spiders, crawlers and replicants
70
70
  email: adam@obledesign.com
71
71
  executables: []
72
72
  extensions: []
73
73
  extra_rdoc_files: []
74
74
  files:
75
- - ".autotest"
76
75
  - ".gitignore"
77
76
  - ".ruby-version"
78
- - CHANGELOG.rdoc
79
77
  - Gemfile
80
78
  - MIT-LICENSE
81
- - README.markdown
82
- - Rakefile
83
- - config/initializers/extend_action_dispatch_request.rb
84
- - config/user_agents.yml
79
+ - README.md
80
+ - config.ru
81
+ - config/crawler-user-agents.json
85
82
  - lib/tasks/voight_kampff.rake
86
83
  - lib/voight_kampff.rb
87
- - lib/voight_kampff/base.rb
88
84
  - lib/voight_kampff/engine.rb
85
+ - lib/voight_kampff/rack_request.rb
89
86
  - lib/voight_kampff/test.rb
90
- - lib/voight_kampff/user_agents_parser.rb
91
87
  - lib/voight_kampff/version.rb
92
- - tests/spec/minitest_helper.rb
93
- - tests/spec/voight_kampff_spec.rb
94
- - tests/test_app/.gitignore
95
- - tests/test_app/Gemfile
96
- - tests/test_app/Gemfile.lock
97
- - tests/test_app/Rakefile
98
- - tests/test_app/app/controllers/application_controller.rb
99
- - tests/test_app/app/helpers/application_helper.rb
100
- - tests/test_app/app/mailers/.gitkeep
101
- - tests/test_app/app/models/.gitkeep
102
- - tests/test_app/app/views/layouts/application.html.erb
103
- - tests/test_app/config.ru
104
- - tests/test_app/config/application.rb
105
- - tests/test_app/config/boot.rb
106
- - tests/test_app/config/database.yml
107
- - tests/test_app/config/environment.rb
108
- - tests/test_app/config/environments/development.rb
109
- - tests/test_app/config/environments/production.rb
110
- - tests/test_app/config/environments/test.rb
111
- - tests/test_app/config/initializers/backtrace_silencers.rb
112
- - tests/test_app/config/initializers/inflections.rb
113
- - tests/test_app/config/initializers/mime_types.rb
114
- - tests/test_app/config/initializers/secret_token.rb
115
- - tests/test_app/config/initializers/session_store.rb
116
- - tests/test_app/config/initializers/wrap_parameters.rb
117
- - tests/test_app/config/locales/en.yml
118
- - tests/test_app/config/routes.rb
119
- - tests/test_app/doc/README_FOR_APP
120
- - tests/test_app/lib/assets/.gitkeep
121
- - tests/test_app/lib/tasks/.gitkeep
122
- - tests/test_app/log/.gitkeep
123
- - tests/test_app/public/404.html
124
- - tests/test_app/public/422.html
125
- - tests/test_app/public/500.html
126
- - tests/test_app/public/favicon.ico
127
- - tests/test_app/public/index.html
128
- - tests/test_app/public/robots.txt
129
- - tests/test_app/script/rails
130
- - tests/test_app/test/fixtures/.gitkeep
131
- - tests/test_app/test/functional/.gitkeep
132
- - tests/test_app/test/integration/.gitkeep
133
- - tests/test_app/test/performance/browsing_test.rb
134
- - tests/test_app/test/test_helper.rb
135
- - tests/test_app/test/unit/.gitkeep
136
- - tests/test_app/vendor/assets/javascripts/.gitkeep
137
- - tests/test_app/vendor/assets/stylesheets/.gitkeep
138
- - tests/test_app/vendor/plugins/.gitkeep
88
+ - spec/controllers/replicants_controller_spec.rb
89
+ - spec/internal/app/controllers/replicants_controller.rb
90
+ - spec/internal/config/routes.rb
91
+ - spec/internal/log/.gitignore
92
+ - spec/internal/public/favicon.ico
93
+ - spec/lib/voight_kampff/rack_request_spec.rb
94
+ - spec/lib/voight_kampff/test_spec.rb
95
+ - spec/lib/voight_kampff_spec.rb
96
+ - spec/spec_helper.rb
97
+ - spec/support/humans.rb
98
+ - spec/support/replicants.rb
139
99
  - voight_kampff.gemspec
140
100
  homepage: https://github.com/biola/Voight-Kampff
141
101
  licenses: