elasticsearch-rails 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ ## 0.1.1
2
+
3
+ * Improved the Rake tasks
4
+ * Improved the example application templates
5
+
6
+ ## 0.1.1 (Initial Version)
data/README.md CHANGED
@@ -78,30 +78,32 @@ You should see the duration of the request to Elasticsearch as part of each log
78
78
 
79
79
  You can generate a fully working example Ruby on Rails application, with an `Article` model and a search form,
80
80
  to play with (it even downloads _Elasticsearch_ itself, generates the application skeleton and leaves you with
81
- a _Git_ repository to explore the steps and the code):
81
+ a _Git_ repository to explore the steps and the code) with the
82
+ [`01-basic.rb`](https://github.com/elasticsearch/elasticsearch-rails/blob/master/elasticsearch-rails/lib/rails/templates/01-basic.rb) template:
82
83
 
83
84
  ```bash
84
85
  rails new searchapp --skip --skip-bundle --template https://raw.github.com/elasticsearch/elasticsearch-rails/master/elasticsearch-rails/lib/rails/templates/01-basic.rb
85
86
  ```
86
87
 
87
- Run the same command again, in the same folder, with the `02-pretty` template to add features such as
88
- a custom `Article.search` method, result highlighting and [_Bootstrap_](http://getbootstrap.com) integration:
88
+ Run the same command again, in the same folder, with the
89
+ [`02-pretty`](https://github.com/elasticsearch/elasticsearch-rails/blob/master/elasticsearch-rails/lib/rails/templates/02-pretty.rb)
90
+ template to add features such as a custom `Article.search` method, result highlighting and
91
+ [_Bootstrap_](http://getbootstrap.com) integration:
89
92
 
90
93
  ```bash
91
94
  rails new searchapp --skip --skip-bundle --template https://raw.github.com/elasticsearch/elasticsearch-rails/master/elasticsearch-rails/lib/rails/templates/02-pretty.rb
92
95
  ```
93
96
 
94
- NOTE: A third, much more complex template, demonstrating other features such as faceted navigation or
95
- query suggestions is being worked on.
97
+ Run the same command with the [`03-expert.rb`](https://github.com/elasticsearch/elasticsearch-rails/blob/master/elasticsearch-rails/lib/rails/templates/03-expert.rb)
98
+ template to refactor the application into a more complex use case,
99
+ with couple of hundreds of The New York Times articles as the example content.
100
+ The template will extract the Elasticsearch integration into a `Searchable` "concern" module,
101
+ define complex mapping, custom serialization, implement faceted navigation and suggestions as a part of
102
+ a complex query, and add a _Sidekiq_-based worker for updating the index in the background.
96
103
 
97
- ## TODO
98
-
99
- This is an initial release of the `elasticsearch-rails` library. Many more features are planned and/or
100
- being worked on, such as:
101
-
102
- * Rake tasks for convenient (re)indexing your models from the command line
103
- * Hooking into Rails' notification system to display Elasticsearch related statistics in the application log
104
- * Instrumentation support for NewRelic integration
104
+ ```bash
105
+ rails new searchapp --skip --skip-bundle --template https://raw.github.com/elasticsearch/elasticsearch-rails/master/elasticsearch-rails/lib/rails/templates/03-expert.rb
106
+ ```
105
107
 
106
108
  ## License
107
109
 
@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
31
31
 
32
32
  s.add_development_dependency "lograge"
33
33
 
34
+ s.add_development_dependency "minitest", "~> 4.0"
34
35
  s.add_development_dependency "shoulda-context"
35
36
  s.add_development_dependency "mocha"
36
37
  s.add_development_dependency "turn"
@@ -56,16 +56,17 @@ namespace :elasticsearch do
56
56
  rescue NoMethodError; end
57
57
  end
58
58
 
59
- klass.import force: ENV.fetch('FORCE', false),
60
- batch_size: ENV.fetch('BATCH', 1000).to_i,
61
- index: ENV.fetch('INDEX', nil),
62
- type: ENV.fetch('TYPE', nil) do |response|
59
+ total_errors = klass.import force: ENV.fetch('FORCE', false),
60
+ batch_size: ENV.fetch('BATCH', 1000).to_i,
61
+ index: ENV.fetch('INDEX', nil),
62
+ type: ENV.fetch('TYPE', nil) do |response|
63
63
  pbar.inc response['items'].size if pbar
64
64
  STDERR.flush
65
65
  STDOUT.flush
66
66
  end
67
67
  pbar.finish if pbar
68
68
 
69
+ puts "[IMPORT] #{total_errors} errors occurred" unless total_errors.zero?
69
70
  puts '[IMPORT] Done'
70
71
  end
71
72
 
@@ -96,6 +97,7 @@ namespace :elasticsearch do
96
97
 
97
98
  ENV['CLASS'] = klass.to_s
98
99
  Rake::Task["elasticsearch:import:model"].invoke
100
+ Rake::Task["elasticsearch:import:model"].reenable
99
101
  puts
100
102
  end
101
103
  end
@@ -1,5 +1,5 @@
1
1
  module Elasticsearch
2
2
  module Rails
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.1"
4
4
  end
5
5
  end
@@ -20,8 +20,8 @@
20
20
  #
21
21
  # =====================================================================================================
22
22
 
23
- require 'elasticsearch'
24
- client = Elasticsearch::Client.new
23
+ require 'uri'
24
+ require 'net/http'
25
25
 
26
26
  at_exit do
27
27
  pid = File.read("#{destination_root}/tmp/pids/elasticsearch.pid") rescue nil
@@ -33,7 +33,7 @@ end
33
33
 
34
34
  run "touch tmp/.gitignore"
35
35
 
36
- append_to_file ".gitignore", "vendor/elasticsearch-0.90.7/\n"
36
+ append_to_file ".gitignore", "vendor/elasticsearch-1.0.1/\n"
37
37
 
38
38
  git :init
39
39
  git add: "."
@@ -41,12 +41,12 @@ git commit: "-m 'Initial commit: Clean application'"
41
41
 
42
42
  # ----- Download Elasticsearch --------------------------------------------------------------------
43
43
 
44
- unless (client.ping rescue false)
44
+ unless (Net::HTTP.get(URI.parse('http://localhost:9200')) rescue false)
45
45
  COMMAND = <<-COMMAND.gsub(/^ /, '')
46
- curl -# -O "http://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-0.90.7.tar.gz"
47
- tar -zxf elasticsearch-0.90.7.tar.gz
48
- rm -f elasticsearch-0.90.7.tar.gz
49
- ./elasticsearch-0.90.7/bin/elasticsearch -p #{destination_root}/tmp/pids/elasticsearch.pid
46
+ curl -# -O "http://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.0.1.tar.gz"
47
+ tar -zxf elasticsearch-1.0.1.tar.gz
48
+ rm -f elasticsearch-1.0.1.tar.gz
49
+ ./elasticsearch-1.0.1/bin/elasticsearch -d -p #{destination_root}/tmp/pids/elasticsearch.pid
50
50
  COMMAND
51
51
 
52
52
  puts "\n"
@@ -70,7 +70,7 @@ unless (client.ping rescue false)
70
70
  run "(#{exec})" # Launch Elasticsearch in subshell
71
71
  end
72
72
  end
73
- end
73
+ end unless ENV['RAILS_NO_ES_INSTALL']
74
74
 
75
75
  # ----- Add README --------------------------------------------------------------------------------
76
76
 
@@ -123,6 +123,7 @@ gem 'mocha', group: 'test', require: 'mocha/setup'
123
123
  comment_lines 'Gemfile', /gem 'coffee/
124
124
  comment_lines 'Gemfile', /gem 'sass/
125
125
  comment_lines 'Gemfile', /gem 'uglifier/
126
+ uncomment_lines 'Gemfile', /gem 'therubyracer/
126
127
 
127
128
  # ----- Add gems into Gemfile ---------------------------------------------------------------------
128
129
 
@@ -134,6 +135,23 @@ gem 'elasticsearch', git: 'git://github.com/elasticsearch/elasticsearch-ru
134
135
  gem 'elasticsearch-model', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'
135
136
  gem 'elasticsearch-rails', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'
136
137
 
138
+
139
+ git add: "Gemfile*"
140
+ git commit: "-m 'Added libraries into Gemfile'"
141
+
142
+ # ----- Disable asset logging in development ------------------------------------------------------
143
+
144
+ puts
145
+ say_status "Application", "Disabling asset logging in development...\n", :yellow
146
+ puts '-'*80, ''; sleep 0.25
147
+
148
+ environment 'config.assets.logger = false', env: 'development'
149
+ gem 'quiet_assets', group: "development"
150
+
151
+ git add: "Gemfile*"
152
+ git add: "config/"
153
+ git commit: "-m 'Disabled asset logging in development'"
154
+
137
155
  # ----- Install gems ------------------------------------------------------------------------------
138
156
 
139
157
  puts
@@ -142,9 +160,6 @@ puts '-'*80, ''
142
160
 
143
161
  run "bundle install"
144
162
 
145
- git add: "Gemfile*"
146
- git commit: "-m 'Added libraries into Gemfile'"
147
-
148
163
  # ----- Generate Article resource -----------------------------------------------------------------
149
164
 
150
165
  puts
@@ -169,6 +184,7 @@ file 'app/models/article.rb', <<-CODE
169
184
  class Article < ActiveRecord::Base
170
185
  include Elasticsearch::Model
171
186
  include Elasticsearch::Model::Callbacks
187
+ #{'attr_accessible :title, :content, :published_on' if Rails::VERSION::STRING < '4'}
172
188
  end
173
189
  CODE
174
190
 
@@ -221,7 +237,7 @@ resources :articles do
221
237
  end
222
238
  CODE
223
239
 
224
- gsub_file 'test/controllers/articles_controller_test.rb', %r{setup do.*?end}m, <<-CODE
240
+ gsub_file "#{Rails::VERSION::STRING > '4' ? 'test/controllers' : 'test/functional'}/articles_controller_test.rb", %r{setup do.*?end}m, <<-CODE
225
241
  setup do
226
242
  @article = articles(:one)
227
243
 
@@ -230,7 +246,7 @@ setup do
230
246
  end
231
247
  CODE
232
248
 
233
- inject_into_file 'test/controllers/articles_controller_test.rb', after: %r{test "should get index" do.*?end}m do
249
+ inject_into_file "#{Rails::VERSION::STRING > '4' ? 'test/controllers' : 'test/functional'}/articles_controller_test.rb", after: %r{test "should get index" do.*?end}m do
234
250
  <<-CODE
235
251
 
236
252
 
@@ -300,19 +316,21 @@ git log: "--reverse --oneline"
300
316
 
301
317
  # ----- Start the application ---------------------------------------------------------------------
302
318
 
303
- require 'net/http'
304
- if (begin; Net::HTTP.get(URI('http://localhost:3000')); rescue Errno::ECONNREFUSED; false; rescue Exception; true; end)
305
- puts "\n"
306
- say_status "ERROR", "Some other application is running on port 3000!\n", :red
307
- puts '-'*80
319
+ unless ENV['RAILS_NO_SERVER_START']
320
+ require 'net/http'
321
+ if (begin; Net::HTTP.get(URI('http://localhost:3000')); rescue Errno::ECONNREFUSED; false; rescue Exception; true; end)
322
+ puts "\n"
323
+ say_status "ERROR", "Some other application is running on port 3000!\n", :red
324
+ puts '-'*80
308
325
 
309
- port = ask("Please provide free port:", :bold)
310
- else
311
- port = '3000'
312
- end
326
+ port = ask("Please provide free port:", :bold)
327
+ else
328
+ port = '3000'
329
+ end
313
330
 
314
- puts "", "="*80
315
- say_status "DONE", "\e[1mStarting the application.\e[0m", :yellow
316
- puts "="*80, ""
331
+ puts "", "="*80
332
+ say_status "DONE", "\e[1mStarting the application.\e[0m", :yellow
333
+ puts "="*80, ""
317
334
 
318
- run "rails server --port=#{port}"
335
+ run "rails server --port=#{port}"
336
+ end
@@ -22,6 +22,19 @@ README
22
22
  git add: "README.rdoc"
23
23
  git commit: "-m '[02] Updated the application README'"
24
24
 
25
+ # ----- Update application.rb ---------------------------------------------------------------------
26
+
27
+ puts
28
+ say_status "Rubygems", "Adding Rails logger integration...\n", :yellow
29
+ puts '-'*80, ''; sleep 0.25
30
+
31
+ insert_into_file 'config/application.rb',
32
+ "\n\nrequire 'elasticsearch/rails/instrumentation'\n",
33
+ after: 'Bundler.require(:default, Rails.env)'
34
+
35
+ git add: "config/application.rb"
36
+ git commit: "-m 'Added the Rails logger integration to application.rb'"
37
+
25
38
  # ----- Add gems into Gemfile ---------------------------------------------------------------------
26
39
 
27
40
  puts
@@ -73,7 +86,7 @@ insert_into_file 'app/models/article.rb', <<-CODE, after: 'include Elasticsearch
73
86
  end
74
87
  CODE
75
88
 
76
- gsub_file "test/models/article_test.rb", %r{# test "the truth" do.*?# end}m, <<-CODE
89
+ gsub_file "#{Rails::VERSION::STRING > '4' ? 'test/models' : 'test/unit' }/article_test.rb", %r{# test "the truth" do.*?# end}m, <<-CODE
77
90
 
78
91
  test "has a search method delegating to __elasticsearch__" do
79
92
  Article.__elasticsearch__.expects(:search).with do |definition|
@@ -85,7 +98,7 @@ gsub_file "test/models/article_test.rb", %r{# test "the truth" do.*?# end}m, <<-
85
98
  CODE
86
99
 
87
100
  git add: "app/models/article.rb"
88
- git add: "test/models/article_test.rb"
101
+ git add: "test/**/article_test.rb"
89
102
  git commit: "-m 'Added an `Article.search` method'"
90
103
 
91
104
  # ----- Add loading Bootstrap assets --------------------------------------------------------------
@@ -266,19 +279,21 @@ git log: "--reverse --oneline pretty...basic"
266
279
 
267
280
  # ----- Start the application ---------------------------------------------------------------------
268
281
 
269
- require 'net/http'
270
- if (begin; Net::HTTP.get(URI('http://localhost:3000')); rescue Errno::ECONNREFUSED; false; rescue Exception; true; end)
271
- puts "\n"
272
- say_status "ERROR", "Some other application is running on port 3000!\n", :red
273
- puts '-'*80
282
+ unless ENV['RAILS_NO_SERVER_START']
283
+ require 'net/http'
284
+ if (begin; Net::HTTP.get(URI('http://localhost:3000')); rescue Errno::ECONNREFUSED; false; rescue Exception; true; end)
285
+ puts "\n"
286
+ say_status "ERROR", "Some other application is running on port 3000!\n", :red
287
+ puts '-'*80
274
288
 
275
- port = ask("Please provide free port:", :bold)
276
- else
277
- port = '3000'
278
- end
289
+ port = ask("Please provide free port:", :bold)
290
+ else
291
+ port = '3000'
292
+ end
279
293
 
280
- puts "", "="*80
281
- say_status "DONE", "\e[1mStarting the application. Open http://localhost:#{port}\e[0m", :yellow
282
- puts "="*80, ""
294
+ puts "", "="*80
295
+ say_status "DONE", "\e[1mStarting the application. Open http://localhost:#{port}\e[0m", :yellow
296
+ puts "="*80, ""
283
297
 
284
- run "rails server --port=#{port}"
298
+ run "rails server --port=#{port}"
299
+ end
@@ -2,113 +2,98 @@
2
2
 
3
3
  # (See: 01-basic.rb, 02-pretty.rb)
4
4
 
5
- # ----- Move the search form into partial ---------------------------------------------------------
5
+ append_to_file 'README.rdoc', <<-README
6
+
7
+ == [3] Expert
8
+
9
+ The `expert` template changes to a complex database schema with model relationships: article belongs
10
+ to a category, has many authors and comments.
11
+
12
+ * The Elasticsearch integration is refactored into the `Searchable` concern
13
+ * A complex mapping for the index is defined
14
+ * A custom serialization is defined in `Article#as_indexed_json`
15
+ * The `search` method is amended with facets and suggestions
16
+ * A [Sidekiq](http://sidekiq.org) worker for handling index updates in background is added
17
+ * A custom `SearchController` with associated view is added
18
+ * A Rails initializer is added to customize the Elasticsearch client configuration
19
+ * Seed script and example data from New York Times is added
20
+
21
+ README
22
+
23
+ git add: "README.rdoc"
24
+ git commit: "-m '[03] Updated the application README'"
25
+
26
+ # ----- Add gems into Gemfile ---------------------------------------------------------------------
6
27
 
7
28
  puts
8
- say_status "View", "Moving the search form into partial template...\n", :yellow
9
- puts '-'*80, ''; sleep 0.5
29
+ say_status "Rubygems", "Adding Rubygems into Gemfile...\n", :yellow
30
+ puts '-'*80, ''; sleep 0.25
10
31
 
11
- gsub_file 'app/views/articles/index.html.erb', %r{\n<hr>.*<hr>\n}m do |match|
12
- create_file "app/views/articles/_search_form.html.erb", match
13
- "\n<%= render partial: 'search_form' %>\n"
14
- end
32
+ gem "oj"
15
33
 
16
- git :add => 'app/views/articles/index.html.erb app/views/articles/_search_form.html.erb'
17
- git :commit => "-m 'Moved the search form into a partial template'"
34
+ git add: "Gemfile*"
35
+ git commit: "-m 'Added Ruby gems'"
18
36
 
19
- # ----- Move the model integration into a concern -------------------------------------------------
37
+ # ----- Customize the Rails console ---------------------------------------------------------------
20
38
 
21
39
  puts
22
- say_status "Model", "Refactoring the model integration...\n", :yellow
23
- puts '-'*80, ''; sleep 0.5
40
+ say_status "Rails", "Customizing `rails console`...\n", :yellow
41
+ puts '-'*80, ''; sleep 0.25
24
42
 
25
- create_file 'app/models/concerns/searchable.rb', <<-CODE
26
- module Searchable
27
- extend ActiveSupport::Concern
28
43
 
29
- included do
30
- include Elasticsearch::Model
31
- end
44
+ gem "pry", group: 'development'
32
45
 
33
- module ClassMethods
34
- def search(query)
35
- __elasticsearch__.search(
36
- {
37
- query: {
38
- multi_match: {
39
- query: query,
40
- fields: ['title^10', 'content']
41
- }
42
- },
43
- highlight: {
44
- pre_tags: ['<em class="label label-highlight">'],
45
- post_tags: ['</em>'],
46
- fields: {
47
- title: { number_of_fragments: 0 },
48
- content: { fragment_size: 25 }
49
- }
50
- }
51
- }
52
- )
53
- end
46
+ environment nil, env: 'development' do
47
+ %q{
48
+ console do
49
+ config.console = Pry
50
+ Pry.config.history.file = Rails.root.join('tmp/console_history.rb').to_s
51
+ Pry.config.prompt = [ proc { |obj, nest_level, _| "(#{obj})> " },
52
+ proc { |obj, nest_level, _| ' '*obj.to_s.size + ' '*(nest_level+1) + '| ' } ]
54
53
  end
54
+ }
55
55
  end
56
- CODE
57
56
 
58
- remove_file 'app/models/article.rb'
59
- create_file 'app/models/article.rb', <<-CODE
60
- class Article < ActiveRecord::Base
61
- include Searchable
62
- end
63
- CODE
57
+ git add: "Gemfile*"
58
+ git add: "config/"
59
+ git commit: "-m 'Added Pry as the console for development'"
64
60
 
65
- git :add => 'app/models/'
66
- git :commit => "-m 'Refactored the Elasticsearch integration into a concern\n\nSee:\n\n* http://37signals.com/svn/posts/3372-put-chubby-models-on-a-diet-with-concerns\n* http://joshsymonds.com/blog/2012/10/25/rails-concerns-v-searchable-with-elasticsearch/'"
67
-
68
- # ----- Add initializer ---------------------------------------------------------------------------
61
+ # ----- Disable asset logging in development ------------------------------------------------------
69
62
 
70
63
  puts
71
- say_status "Application", "Adding configuration in an initializer...\n", :yellow
72
- puts '-'*80, ''; sleep 0.5
64
+ say_status "Application", "Disabling asset logging in development...\n", :yellow
65
+ puts '-'*80, ''; sleep 0.25
73
66
 
74
- create_file 'config/initializers/elasticsearch.rb', <<-CODE
75
- # Connect to specific Elasticsearch cluster
76
- ELASTICSEARCH_URL = ENV['ELASTICSEARCH_URL'] || 'http://localhost:9200'
67
+ environment 'config.assets.logger = false', env: 'development'
68
+ gem 'quiet_assets', group: "development"
77
69
 
78
- # Print Curl-formatted traces in development
79
- #
80
- if Rails.env.development?
81
- tracer = ActiveSupport::Logger.new(STDERR)
82
- tracer.level = Logger::INFO
83
- end
70
+ git add: "Gemfile*"
71
+ git add: "config/"
72
+ git commit: "-m 'Disabled asset logging in development'"
84
73
 
85
- Elasticsearch::Model.client Elasticsearch::Client.new tracer: tracer, host: ELASTICSEARCH_URL
86
- CODE
74
+ # ----- Run bundle install ------------------------------------------------------------------------
87
75
 
88
- git :add => 'config/initializers'
89
- git :commit => "-m 'Added application initializer with Elasticsearch configuration'"
76
+ run "bundle install"
90
77
 
91
- # ----- Generate and define data model for books --------------------------------------------------
78
+ # ----- Define and generate schema ----------------------------------------------------------------
92
79
 
93
80
  puts
94
- say_status "Database", "Adding complex schema and data for books...\n", :yellow
95
- puts '-'*80, ''; sleep 0.5
81
+ say_status "Models", "Adding complex schema...\n", :yellow
82
+ puts '-'*80, ''
96
83
 
97
84
  generate :scaffold, "Category title"
98
- generate :scaffold, "Book title:string content:text downloads:integer category:references"
99
85
  generate :scaffold, "Author first_name last_name"
100
- generate :scaffold, "Authorship book:references author:references"
86
+ generate :scaffold, "Authorship article:references author:references"
101
87
 
102
- insert_into_file "app/models/category.rb", :before => "end" do
103
- <<-CODE
104
- has_many :books
105
- CODE
106
- end
88
+ generate :model, "Comment body:text user:string user_location:string stars:integer pick:boolean article:references"
89
+ generate :migration, "CreateArticlesCategories article:references category:references"
90
+
91
+ rake "db:drop"
92
+ rake "db:migrate"
107
93
 
108
- insert_into_file "app/models/book.rb", :before => "end" do
94
+ insert_into_file "app/models/category.rb", :before => "end" do
109
95
  <<-CODE
110
- has_many :authorships
111
- has_many :authors, through: :authorships
96
+ has_and_belongs_to_many :articles
112
97
  CODE
113
98
  end
114
99
 
@@ -122,764 +107,192 @@ insert_into_file "app/models/author.rb", :before => "end" do
122
107
  CODE
123
108
  end
124
109
 
125
- # ----- Migrate the database --------------------------------------------------------------------------
110
+ gsub_file "app/models/authorship.rb", %r{belongs_to :article$}, <<-CODE
111
+ belongs_to :article, touch: true
112
+ CODE
113
+
114
+ insert_into_file "app/models/article.rb", after: "ActiveRecord::Base" do
115
+ <<-CODE
116
+
117
+ has_and_belongs_to_many :categories, after_add: [ lambda { |a,c| Indexer.perform_async(:update, a.class.to_s, a.id) } ],
118
+ after_remove: [ lambda { |a,c| Indexer.perform_async(:update, a.class.to_s, a.id) } ]
119
+ has_many :authorships
120
+ has_many :authors, through: :authorships
121
+ has_many :comments
122
+ CODE
123
+ end
124
+
125
+ gsub_file "app/models/comment.rb", %r{belongs_to :article$}, <<-CODE
126
+ belongs_to :article, touch: true
127
+ CODE
126
128
 
127
- rake "db:migrate"
129
+ git add: "."
130
+ git commit: "-m 'Generated Category, Author and Comment resources'"
128
131
 
129
- # ----- Create the seed data --------------------------------------------------------------------------
132
+ # ----- Add the `abstract` column -----------------------------------------------------------------
130
133
 
131
- remove_file 'db/seeds.rb'
132
- create_file 'db/seeds.rb', <<-CODE
133
- # encoding: UTF-8
134
-
135
- require 'yaml'
136
-
137
- books = YAML.parse <<-DATA
138
- ---
139
- - :title: Dracula
140
- :authors:
141
- - :last_name: Stoker
142
- :first_name: Bram
143
- :downloads: 12197
144
- :category: Fiction
145
- :content: |
146
- _3 May. Bistritz._--Left Munich at 8:35 P. M., on 1st May, arriving at
147
- Vienna early next morning; should have arrived at 6:46, but train was an
148
- hour late. Buda-Pesth seems a wonderful place, from the glimpse which I
149
- got of it from the train and the little I could walk through the
150
- streets. I feared to go very far from the station, as we had arrived
151
- late and would start as near the correct time as possible. The
152
- impression I had was that we were leaving the West and entering the
153
- East; the most western of splendid bridges over the Danube, which is
154
- here of noble width and depth, took us among the traditions of Turkish
155
- rule.
156
-
157
- We left in pretty good time, and came after nightfall to Klausenburgh.
158
- Here I stopped for the night at the Hotel Royale. I had for dinner, or
159
- rather supper, a chicken done up some way with red pepper, which was
160
- very good but thirsty. (_Mem._, get recipe for Mina.) I asked the
161
- waiter, and he said it was called "paprika hendl," and that, as it was a
162
- national dish, I should be able to get it anywhere along the
163
- Carpathians. I found my smattering of German very useful here; indeed, I
164
- don't know how I should be able to get on without it.
165
-
166
- Having had some time at my disposal when in London, I had visited the
167
- British Museum, and made search among the books and maps in the library
168
- regarding Transylvania; it had struck me that some foreknowledge of the
169
- country could hardly fail to have some importance in dealing with a
170
- nobleman of that country. I find that the district he named is in the
171
- extreme east of the country, just on the borders of three states,
172
- Transylvania, Moldavia and Bukovina, in the midst of the Carpathian
173
- mountains; one of the wildest and least known portions of Europe. I was
174
- not able to light on any map or work giving the exact locality of the
175
- Castle Dracula, as there are no maps of this country as yet to compare
176
- with our own Ordnance Survey maps; but I found that Bistritz, the post
177
- town named by Count Dracula, is a fairly well-known place. I shall enter
178
- here some of my notes, as they may refresh my memory when I talk over my
179
- travels with Mina.
180
-
181
- In the population of Transylvania there are four distinct nationalities:
182
- Saxons in the South, and mixed with them the Wallachs, who are the
183
- descendants of the Dacians; Magyars in the West, and Szekelys in the
184
- East and North. I am going among the latter, who claim to be descended
185
- from Attila and the Huns. This may be so, for when the Magyars conquered
186
- the country in the eleventh century they found the Huns settled in it. I
187
- read that every known superstition in the world is gathered into the
188
- horseshoe of the Carpathians, as if it were the centre of some sort of
189
- imaginative whirlpool; if so my stay may be very interesting. (_Mem._, I
190
- must ask the Count all about them.)
191
-
192
- I did not sleep well, though my bed was comfortable enough, for I had
193
- all sorts of queer dreams. There was a dog howling all night under my
194
- window, which may have had something to do with it; or it may have been
195
- the paprika, for I had to drink up all the water in my carafe, and was
196
- still thirsty. Towards morning I slept and was wakened by the continuous
197
- knocking at my door, so I guess I must have been sleeping soundly then.
198
- I had for breakfast more paprika, and a sort of porridge of maize flour
199
- which they said was "mamaliga," and egg-plant stuffed with forcemeat, a
200
- very excellent dish, which they call "impletata." (_Mem._, get recipe
201
- for this also.) I had to hurry breakfast, for the train started a little
202
- before eight, or rather it ought to have done so, for after rushing to
203
- the station at 7:30 I had to sit in the carriage for more than an hour
204
- before we began to move. It seems to me that the further east you go the
205
- more unpunctual are the trains. What ought they to be in China?
206
-
207
- All day long we seemed to dawdle through a country which was full of
208
- beauty of every kind. Sometimes we saw little towns or castles on the
209
- top of steep hills such as we see in old missals; sometimes we ran by
210
- rivers and streams which seemed from the wide stony margin on each side
211
- of them to be subject to great floods. It takes a lot of water, and
212
- running strong, to sweep the outside edge of a river clear. At every
213
- station there were groups of people, sometimes crowds, and in all sorts
214
- of attire. Some of them were just like the peasants at home or those I
215
- saw coming through France and Germany, with short jackets and round hats
216
- and home-made trousers; but others were very picturesque. The women
217
- looked pretty, except when you got near them, but they were very clumsy
218
- about the waist. They had all full white sleeves of some kind or other,
219
- and most of them had big belts with a lot of strips of something
220
- fluttering from them like the dresses in a ballet, but of course there
221
- were petticoats under them. The strangest figures we saw were the
222
- Slovaks, who were more barbarian than the rest, with their big cow-boy
223
- hats, great baggy dirty-white trousers, white linen shirts, and enormous
224
- heavy leather belts, nearly a foot wide, all studded over with brass
225
- nails. They wore high boots, with their trousers tucked into them, and
226
- had long black hair and heavy black moustaches. They are very
227
- picturesque, but do not look prepossessing. On the stage they would be
228
- set down at once as some old Oriental band of brigands. They are,
229
- however, I am told, very harmless and rather wanting in natural
230
- self-assertion.
231
-
232
- It was on the dark side of twilight when we got to Bistritz, which is a
233
- very interesting old place. Being practically on the frontier--for the
234
- Borgo Pass leads from it into Bukovina--it has had a very stormy
235
- existence, and it certainly shows marks of it. Fifty years ago a series
236
- of great fires took place, which made terrible havoc on five separate
237
- occasions. At the very beginning of the seventeenth century it underwent
238
- a siege of three weeks and lost 13,000 people, the casualties of war
239
- proper being assisted by famine and disease.
240
-
241
- Count Dracula had directed me to go to the Golden Krone Hotel, which I
242
- found, to my great delight, to be thoroughly old-fashioned, for of
243
- course I wanted to see all I could of the ways of the country. I was
244
- evidently expected, for when I got near the door I faced a
245
- cheery-looking elderly woman in the usual peasant dress--white
246
- undergarment with long double apron, front, and back, of coloured stuff
247
- fitting almost too tight for modesty. When I came close she bowed and
248
- said, "The Herr Englishman?" "Yes," I said, "Jonathan Harker." She
249
- smiled, and gave some message to an elderly man in white shirt-sleeves,
250
- who had followed her to the door. He went, but immediately returned with
251
- a letter:--
252
-
253
- "My Friend.--Welcome to the Carpathians. I am anxiously expecting
254
- you. Sleep well to-night. At three to-morrow the diligence will
255
- start for Bukovina; a place on it is kept for you. At the Borgo
256
- Pass my carriage will await you and will bring you to me. I trust
257
- that your journey from London has been a happy one, and that you
258
- will enjoy your stay in my beautiful land.
259
-
260
- "Your friend,
261
-
262
- "DRACULA."
263
-
264
- - :title: Beyond Good and Evil
265
- :authors:
266
- - :last_name: Nietzsche
267
- :first_name: Friedrich Wilhelm
268
- :downloads: 8222
269
- :category: Philosophy
270
- :content: |
271
- SUPPOSING that Truth is a woman--what then? Is there not ground
272
- for suspecting that all philosophers, in so far as they have been
273
- dogmatists, have failed to understand women--that the terrible
274
- seriousness and clumsy importunity with which they have usually paid
275
- their addresses to Truth, have been unskilled and unseemly methods for
276
- winning a woman? Certainly she has never allowed herself to be won; and
277
- at present every kind of dogma stands with sad and discouraged mien--IF,
278
- indeed, it stands at all! For there are scoffers who maintain that it
279
- has fallen, that all dogma lies on the ground--nay more, that it is at
280
- its last gasp. But to speak seriously, there are good grounds for hoping
281
- that all dogmatizing in philosophy, whatever solemn, whatever conclusive
282
- and decided airs it has assumed, may have been only a noble puerilism
283
- and tyronism; and probably the time is at hand when it will be once
284
- and again understood WHAT has actually sufficed for the basis of such
285
- imposing and absolute philosophical edifices as the dogmatists have
286
- hitherto reared: perhaps some popular superstition of immemorial time
287
- (such as the soul-superstition, which, in the form of subject- and
288
- ego-superstition, has not yet ceased doing mischief): perhaps some
289
- play upon words, a deception on the part of grammar, or an
290
- audacious generalization of very restricted, very personal, very
291
- human--all-too-human facts. The philosophy of the dogmatists, it is to
292
- be hoped, was only a promise for thousands of years afterwards, as was
293
- astrology in still earlier times, in the service of which probably more
294
- labour, gold, acuteness, and patience have been spent than on any
295
- actual science hitherto: we owe to it, and to its "super-terrestrial"
296
- pretensions in Asia and Egypt, the grand style of architecture. It seems
297
- that in order to inscribe themselves upon the heart of humanity with
298
- everlasting claims, all great things have first to wander about the
299
- earth as enormous and awe-inspiring caricatures: dogmatic philosophy has
300
- been a caricature of this kind--for instance, the Vedanta doctrine in
301
- Asia, and Platonism in Europe. Let us not be ungrateful to it, although
302
- it must certainly be confessed that the worst, the most tiresome,
303
- and the most dangerous of errors hitherto has been a dogmatist
304
- error--namely, Plato's invention of Pure Spirit and the Good in Itself.
305
- But now when it has been surmounted, when Europe, rid of this nightmare,
306
- can again draw breath freely and at least enjoy a healthier--sleep,
307
- we, WHOSE DUTY IS WAKEFULNESS ITSELF, are the heirs of all the strength
308
- which the struggle against this error has fostered. It amounted to
309
- the very inversion of truth, and the denial of the PERSPECTIVE--the
310
- fundamental condition--of life, to speak of Spirit and the Good as Plato
311
- spoke of them; indeed one might ask, as a physician: "How did such a
312
- malady attack that finest product of antiquity, Plato? Had the wicked
313
- Socrates really corrupted him? Was Socrates after all a corrupter of
314
- youths, and deserved his hemlock?" But the struggle against Plato,
315
- or--to speak plainer, and for the "people"--the struggle against
316
- the ecclesiastical oppression of millenniums of Christianity (FOR
317
- CHRISTIANITY IS PLATONISM FOR THE "PEOPLE"), produced in Europe
318
- a magnificent tension of soul, such as had not existed anywhere
319
- previously; with such a tensely strained bow one can now aim at the
320
- furthest goals. As a matter of fact, the European feels this tension as
321
- a state of distress, and twice attempts have been made in grand style to
322
- unbend the bow: once by means of Jesuitism, and the second time by means
323
- of democratic enlightenment--which, with the aid of liberty of the press
324
- and newspaper-reading, might, in fact, bring it about that the spirit
325
- would not so easily find itself in "distress"! (The Germans invented
326
- gunpowder--all credit to them! but they again made things square--they
327
- invented printing.) But we, who are neither Jesuits, nor democrats,
328
- nor even sufficiently Germans, we GOOD EUROPEANS, and free, VERY free
329
- spirits--we have it still, all the distress of spirit and all the
330
- tension of its bow! And perhaps also the arrow, the duty, and, who
331
- knows? THE GOAL TO AIM AT....
332
-
333
- Sils Maria Upper Engadine, JUNE, 1885.
334
-
335
- - :title: Ulysses
336
- :authors:
337
- - :last_name: Joyce
338
- :first_name: James
339
- :downloads: 14679
340
- :category: Fiction
341
- :content: |
342
- Stately, plump Buck Mulligan came from the stairhead, bearing a bowl of
343
- lather on which a mirror and a razor lay crossed. A yellow dressinggown,
344
- ungirdled, was sustained gently behind him on the mild morning air. He
345
- held the bowl aloft and intoned:
346
-
347
- --_Introibo ad altare Dei_.
348
-
349
- Halted, he peered down the dark winding stairs and called out coarsely:
350
-
351
- --Come up, Kinch! Come up, you fearful jesuit!
352
-
353
- Solemnly he came forward and mounted the round gunrest. He faced about
354
- and blessed gravely thrice the tower, the surrounding land and the
355
- awaking mountains. Then, catching sight of Stephen Dedalus, he bent
356
- towards him and made rapid crosses in the air, gurgling in his throat
357
- and shaking his head. Stephen Dedalus, displeased and sleepy, leaned
358
- his arms on the top of the staircase and looked coldly at the shaking
359
- gurgling face that blessed him, equine in its length, and at the light
360
- untonsured hair, grained and hued like pale oak.
361
-
362
- Buck Mulligan peeped an instant under the mirror and then covered the
363
- bowl smartly.
364
-
365
- --Back to barracks! he said sternly.
366
-
367
- He added in a preacher's tone:
368
-
369
- --For this, O dearly beloved, is the genuine Christine: body and soul
370
- and blood and ouns. Slow music, please. Shut your eyes, gents. One
371
- moment. A little trouble about those white corpuscles. Silence, all.
372
-
373
- He peered sideways up and gave a long slow whistle of call, then paused
374
- awhile in rapt attention, his even white teeth glistening here and there
375
- with gold points. Chrysostomos. Two strong shrill whistles answered
376
- through the calm.
377
-
378
- --Thanks, old chap, he cried briskly. That will do nicely. Switch off
379
- the current, will you?
380
-
381
- He skipped off the gunrest and looked gravely at his watcher, gathering
382
- about his legs the loose folds of his gown. The plump shadowed face and
383
- sullen oval jowl recalled a prelate, patron of arts in the middle ages.
384
- A pleasant smile broke quietly over his lips.
385
-
386
- --The mockery of it! he said gaily. Your absurd name, an ancient Greek!
387
-
388
- He pointed his finger in friendly jest and went over to the parapet,
389
- laughing to himself. Stephen Dedalus stepped up, followed him wearily
390
- halfway and sat down on the edge of the gunrest, watching him still as
391
- he propped his mirror on the parapet, dipped the brush in the bowl and
392
- lathered cheeks and neck.
393
-
394
- Buck Mulligan's gay voice went on.
395
-
396
- --My name is absurd too: Malachi Mulligan, two dactyls. But it has a
397
- Hellenic ring, hasn't it? Tripping and sunny like the buck himself.
398
- We must go to Athens. Will you come if I can get the aunt to fork out
399
- twenty quid?
400
-
401
- He laid the brush aside and, laughing with delight, cried:
402
-
403
- --Will he come? The jejune jesuit!
404
-
405
- Ceasing, he began to shave with care.
406
-
407
- --Tell me, Mulligan, Stephen said quietly.
408
-
409
- --Yes, my love?
410
-
411
- --How long is Haines going to stay in this tower?
412
-
413
- Buck Mulligan showed a shaven cheek over his right shoulder.
414
-
415
- - :title: Metamorphosis
416
- :authors:
417
- - :last_name: Kafka
418
- :first_name: Franz
419
- :downloads: 22697
420
- :category: Fiction
421
- :content: |
422
- One morning, when Gregor Samsa woke from troubled dreams, he found
423
- himself transformed in his bed into a horrible vermin. He lay on
424
- his armour-like back, and if he lifted his head a little he could
425
- see his brown belly, slightly domed and divided by arches into stiff
426
- sections. The bedding was hardly able to cover it and seemed ready
427
- to slide off any moment. His many legs, pitifully thin compared
428
- with the size of the rest of him, waved about helplessly as he
429
- looked.
430
-
431
- "What's happened to me?" he thought. It wasn't a dream. His room,
432
- a proper human room although a little too small, lay peacefully
433
- between its four familiar walls. A collection of textile samples
434
- lay spread out on the table - Samsa was a travelling salesman - and
435
- above it there hung a picture that he had recently cut out of an
436
- illustrated magazine and housed in a nice, gilded frame. It showed
437
- a lady fitted out with a fur hat and fur boa who sat upright,
438
- raising a heavy fur muff that covered the whole of her lower arm
439
- towards the viewer.
440
-
441
- Gregor then turned to look out the window at the dull weather.
442
- Drops of rain could be heard hitting the pane, which made him feel
443
- quite sad. "How about if I sleep a little bit longer and forget all
444
- this nonsense", he thought, but that was something he was unable to
445
- do because he was used to sleeping on his right, and in his present
446
- state couldn't get into that position. However hard he threw
447
- himself onto his right, he always rolled back to where he was. He
448
- must have tried it a hundred times, shut his eyes so that he
449
- wouldn't have to look at the floundering legs, and only stopped when
450
- he began to feel a mild, dull pain there that he had never felt
451
- before.
452
-
453
- "Oh, God", he thought, "what a strenuous career it is that I've
454
- chosen! Travelling day in and day out. Doing business like this
455
- takes much more effort than doing your own business at home, and on
456
- top of that there's the curse of travelling, worries about making
457
- train connections, bad and irregular food, contact with different
458
- people all the time so that you can never get to know anyone or
459
- become friendly with them. It can all go to Hell!" He felt a
460
- slight itch up on his belly; pushed himself slowly up on his back
461
- towards the headboard so that he could lift his head better; found
462
- where the itch was, and saw that it was covered with lots of little
463
- white spots which he didn't know what to make of; and when he tried
464
- to feel the place with one of his legs he drew it quickly back
465
- because as soon as he touched it he was overcome by a cold shudder.
466
-
467
- He slid back into his former position. "Getting up early all the
468
- time", he thought, "it makes you stupid. You've got to get enough
469
- sleep. Other travelling salesmen live a life of luxury. For
470
- instance, whenever I go back to the guest house during the morning
471
- to copy out the contract, these gentlemen are always still sitting
472
- there eating their breakfasts. I ought to just try that with my
473
- boss; I'd get kicked out on the spot. But who knows, maybe that
474
- would be the best thing for me. If I didn't have my parents to
475
- think about I'd have given in my notice a long time ago, I'd have
476
- gone up to the boss and told him just what I think, tell him
477
- everything I would, let him know just what I feel. He'd fall right
478
- off his desk! And it's a funny sort of business to be sitting up
479
- there at your desk, talking down at your subordinates from up there,
480
- especially when you have to go right up close because the boss is
481
- hard of hearing. Well, there's still some hope; once I've got the
482
- money together to pay off my parents' debt to him - another five or
483
- six years I suppose - that's definitely what I'll do. That's when
484
- I'll make the big change. First of all though, I've got to get up,
485
- my train leaves at five."
486
-
487
- - :title: Crime and Punishment
488
- :authors:
489
- - :last_name: Dostoyevsky
490
- :first_name: Fyodor
491
- :downloads: 4590
492
- :category: Fiction
493
- :content: |
494
- On an exceptionally hot evening early in July a young man came out of
495
- the garret in which he lodged in S. Place and walked slowly, as though
496
- in hesitation, towards K. bridge.
497
-
498
- He had successfully avoided meeting his landlady on the staircase. His
499
- garret was under the roof of a high, five-storied house and was more
500
- like a cupboard than a room. The landlady who provided him with garret,
501
- dinners, and attendance, lived on the floor below, and every time
502
- he went out he was obliged to pass her kitchen, the door of which
503
- invariably stood open. And each time he passed, the young man had a
504
- sick, frightened feeling, which made him scowl and feel ashamed. He was
505
- hopelessly in debt to his landlady, and was afraid of meeting her.
506
-
507
- This was not because he was cowardly and abject, quite the contrary; but
508
- for some time past he had been in an overstrained irritable condition,
509
- verging on hypochondria. He had become so completely absorbed in
510
- himself, and isolated from his fellows that he dreaded meeting, not
511
- only his landlady, but anyone at all. He was crushed by poverty, but the
512
- anxieties of his position had of late ceased to weigh upon him. He had
513
- given up attending to matters of practical importance; he had lost all
514
- desire to do so. Nothing that any landlady could do had a real terror
515
- for him. But to be stopped on the stairs, to be forced to listen to her
516
- trivial, irrelevant gossip, to pestering demands for payment, threats
517
- and complaints, and to rack his brains for excuses, to prevaricate, to
518
- lie--no, rather than that, he would creep down the stairs like a cat and
519
- slip out unseen.
520
-
521
- This evening, however, on coming out into the street, he became acutely
522
- aware of his fears.
523
-
524
- "I want to attempt a thing _like that_ and am frightened by these
525
- trifles," he thought, with an odd smile. "Hm... yes, all is in a man's
526
- hands and he lets it all slip from cowardice, that's an axiom. It would
527
- be interesting to know what it is men are most afraid of. Taking a new
528
- step, uttering a new word is what they fear most.... But I am talking
529
- too much. It's because I chatter that I do nothing. Or perhaps it is
530
- that I chatter because I do nothing. I've learned to chatter this
531
- last month, lying for days together in my den thinking... of Jack the
532
- Giant-killer. Why am I going there now? Am I capable of _that_? Is
533
- _that_ serious? It is not serious at all. It's simply a fantasy to amuse
534
- myself; a plaything! Yes, maybe it is a plaything."
535
-
536
- The heat in the street was terrible: and the airlessness, the bustle
537
- and the plaster, scaffolding, bricks, and dust all about him, and that
538
- special Petersburg stench, so familiar to all who are unable to get out
539
- of town in summer--all worked painfully upon the young man's already
540
- overwrought nerves. The insufferable stench from the pot-houses, which
541
- are particularly numerous in that part of the town, and the drunken men
542
- whom he met continually, although it was a working day, completed
543
- the revolting misery of the picture. An expression of the profoundest
544
- disgust gleamed for a moment in the young man's refined face. He was,
545
- by the way, exceptionally handsome, above the average in height, slim,
546
- well-built, with beautiful dark eyes and dark brown hair. Soon he sank
547
- into deep thought, or more accurately speaking into a complete blankness
548
- of mind; he walked along not observing what was about him and not caring
549
- to observe it. From time to time, he would mutter something, from the
550
- habit of talking to himself, to which he had just confessed. At these
551
- moments he would become conscious that his ideas were sometimes in a
552
- tangle and that he was very weak; for two days he had scarcely tasted
553
- food.
554
-
555
- - :title: The Hound of the Baskervilles
556
- :authors:
557
- - :last_name: Doyle
558
- :first_name: Arthur Conan
559
- :downloads: 5021
560
- :category: Fiction
561
- :content: |
562
- Mr. Sherlock Holmes, who was usually very late in the mornings, save
563
- upon those not infrequent occasions when he was up all night, was seated
564
- at the breakfast table. I stood upon the hearth-rug and picked up the
565
- stick which our visitor had left behind him the night before. It was a
566
- fine, thick piece of wood, bulbous-headed, of the sort which is known as
567
- a "Penang lawyer." Just under the head was a broad silver band nearly
568
- an inch across. "To James Mortimer, M.R.C.S., from his friends of the
569
- C.C.H.," was engraved upon it, with the date "1884." It was just such a
570
- stick as the old-fashioned family practitioner used to carry--dignified,
571
- solid, and reassuring.
572
-
573
- "Well, Watson, what do you make of it?"
574
-
575
- Holmes was sitting with his back to me, and I had given him no sign of
576
- my occupation.
577
-
578
- "How did you know what I was doing? I believe you have eyes in the back
579
- of your head."
580
-
581
- "I have, at least, a well-polished, silver-plated coffee-pot in front of
582
- me," said he. "But, tell me, Watson, what do you make of our visitor's
583
- stick? Since we have been so unfortunate as to miss him and have no
584
- notion of his errand, this accidental souvenir becomes of importance.
585
- Let me hear you reconstruct the man by an examination of it."
586
-
587
- "I think," said I, following as far as I could the methods of my
588
- companion, "that Dr. Mortimer is a successful, elderly medical man,
589
- well-esteemed since those who know him give him this mark of their
590
- appreciation."
591
-
592
- "Good!" said Holmes. "Excellent!"
593
-
594
- "I think also that the probability is in favour of his being a country
595
- practitioner who does a great deal of his visiting on foot."
596
-
597
- "Why so?"
598
-
599
- "Because this stick, though originally a very handsome one has been so
600
- knocked about that I can hardly imagine a town practitioner carrying it.
601
- The thick-iron ferrule is worn down, so it is evident that he has done a
602
- great amount of walking with it."
603
-
604
- "Perfectly sound!" said Holmes.
605
-
606
- "And then again, there is the 'friends of the C.C.H.' I should guess
607
- that to be the Something Hunt, the local hunt to whose members he has
608
- possibly given some surgical assistance, and which has made him a small
609
- presentation in return."
610
-
611
- "Really, Watson, you excel yourself," said Holmes, pushing back his
612
- chair and lighting a cigarette. "I am bound to say that in all the
613
- accounts which you have been so good as to give of my own small
614
- achievements you have habitually underrated your own abilities. It may
615
- be that you are not yourself luminous, but you are a conductor of
616
- light. Some people without possessing genius have a remarkable power of
617
- stimulating it. I confess, my dear fellow, that I am very much in your
618
- debt."
619
-
620
- He had never said as much before, and I must admit that his words gave
621
- me keen pleasure, for I had often been piqued by his indifference to my
622
- admiration and to the attempts which I had made to give publicity to
623
- his methods. I was proud, too, to think that I had so far mastered his
624
- system as to apply it in a way which earned his approval. He now took
625
- the stick from my hands and examined it for a few minutes with his naked
626
- eyes. Then with an expression of interest he laid down his cigarette,
627
- and carrying the cane to the window, he looked over it again with a
628
- convex lens.
629
-
630
- "Interesting, though elementary," said he as he returned to his
631
- favourite corner of the settee. "There are certainly one or two
632
- indications upon the stick. It gives us the basis for several
633
- deductions."
634
-
635
- - :title: Madame Bovary
636
- :authors:
637
- - :last_name: Flaubert
638
- :first_name: Gustave
639
- :downloads: 4090
640
- :category: Fiction
641
- :content: |
642
- We were in class when the head-master came in, followed by a "new
643
- fellow," not wearing the school uniform, and a school servant carrying a
644
- large desk. Those who had been asleep woke up, and every one rose as if
645
- just surprised at his work.
646
-
647
- The head-master made a sign to us to sit down. Then, turning to the
648
- class-master, he said to him in a low voice--
649
-
650
- "Monsieur Roger, here is a pupil whom I recommend to your care; he'll be
651
- in the second. If his work and conduct are satisfactory, he will go into
652
- one of the upper classes, as becomes his age."
653
-
654
- The "new fellow," standing in the corner behind the door so that he
655
- could hardly be seen, was a country lad of about fifteen, and taller
656
- than any of us. His hair was cut square on his forehead like a village
657
- chorister's; he looked reliable, but very ill at ease. Although he was
658
- not broad-shouldered, his short school jacket of green cloth with black
659
- buttons must have been tight about the arm-holes, and showed at the
660
- opening of the cuffs red wrists accustomed to being bare. His legs, in
661
- blue stockings, looked out from beneath yellow trousers, drawn tight by
662
- braces, He wore stout, ill-cleaned, hob-nailed boots.
663
-
664
- We began repeating the lesson. He listened with all his ears, as
665
- attentive as if at a sermon, not daring even to cross his legs or lean
666
- on his elbow; and when at two o'clock the bell rang, the master was
667
- obliged to tell him to fall into line with the rest of us.
668
-
669
- When we came back to work, we were in the habit of throwing our caps on
670
- the ground so as to have our hands more free; we used from the door to
671
- toss them under the form, so that they hit against the wall and made a
672
- lot of dust: it was "the thing."
673
-
674
- But, whether he had not noticed the trick, or did not dare to attempt
675
- it, the "new fellow," was still holding his cap on his knees even after
676
- prayers were over. It was one of those head-gears of composite order, in
677
- which we can find traces of the bearskin, shako, billycock hat, sealskin
678
- cap, and cotton night-cap; one of those poor things, in fine, whose
679
- dumb ugliness has depths of expression, like an imbecile's face. Oval,
680
- stiffened with whalebone, it began with three round knobs; then came in
681
- succession lozenges of velvet and rabbit-skin separated by a red band;
682
- after that a sort of bag that ended in a cardboard polygon covered with
683
- complicated braiding, from which hung, at the end of a long thin cord,
684
- small twisted gold threads in the manner of a tassel. The cap was new;
685
- its peak shone.
686
-
687
- "Rise," said the master.
688
-
689
- He stood up; his cap fell. The whole class began to laugh. He stooped to
690
- pick it up. A neighbor knocked it down again with his elbow; he picked
691
- it up once more.
692
-
693
- - :title: Tractatus Logico-Philosophicus
694
- :authors:
695
- - :last_name: Wittgenstein
696
- :first_name: Ludwig
697
- :downloads: 4036
698
- :category: Philosophy
699
- :content: |
700
- 1 The world is everything that is the case.∗
701
- 1.1 The world is the totality of facts, not of things.
702
- 1.11 The world is determined by the facts, and by these being all the facts.
703
- 1.12 For the totality of facts determines both what is the case, and also all that is not the case.
704
- 1.13 The facts in logical space are the world.
705
- 1.2 The world divides into facts.
706
- 1.21 Any one can either be the case or not be the case, and everything else remain the same.
707
- - :title: A General Introduction to Psychoanalysis
708
- :authors:
709
- - :last_name: Freud
710
- :first_name: Sigmund
711
- :downloads: 1355
712
- :category: Psychology
713
- :content: |
714
- I do not know how familiar some of you may be, either from your reading
715
- or from hearsay, with psychoanalysis. But, in keeping with the title of
716
- these lectures--_A General Introduction to Psychoanalysis_--I am obliged
717
- to proceed as though you knew nothing about this subject, and stood in
718
- need of preliminary instruction.
719
-
720
- To be sure, this much I may presume that you do know, namely, that
721
- psychoanalysis is a method of treating nervous patients medically. And
722
- just at this point I can give you an example to illustrate how the
723
- procedure in this field is precisely the reverse of that which is the
724
- rule in medicine. Usually when we introduce a patient to a medical
725
- technique which is strange to him we minimize its difficulties and give
726
- him confident promises concerning the result of the treatment. When,
727
- however, we undertake psychoanalytic treatment with a neurotic patient
728
- we proceed differently. We hold before him the difficulties of the
729
- method, its length, the exertions and the sacrifices which it will cost
730
- him; and, as to the result, we tell him that we make no definite
731
- promises, that the result depends on his conduct, on his understanding,
732
- on his adaptability, on his perseverance. We have, of course, excellent
733
- motives for conduct which seems so perverse, and into which you will
734
- perhaps gain insight at a later point in these lectures.
735
-
736
- Do not be offended, therefore, if, for the present, I treat you as I
737
- treat these neurotic patients. Frankly, I shall dissuade you from coming
738
- to hear me a second time. With this intention I shall show what
739
- imperfections are necessarily involved in the teaching of psychoanalysis
740
- and what difficulties stand in the way of gaining a personal judgment. I
741
- shall show you how the whole trend of your previous training and all
742
- your accustomed mental habits must unavoidably have made you opponents
743
- of psychoanalysis, and how much you must overcome in yourselves in
744
- order to master this instinctive opposition. Of course I cannot predict
745
- how much psychoanalytic understanding you will gain from my lectures,
746
- but I can promise this, that by listening to them you will not learn how
747
- to undertake a psychoanalytic treatment or how to carry one to
748
- completion. Furthermore, should I find anyone among you who does not
749
- feel satisfied with a cursory acquaintance with psychoanalysis, but who
750
- would like to enter into a more enduring relationship with it, I shall
751
- not only dissuade him, but I shall actually warn him against it. As
752
- things now stand, a person would, by such a choice of profession, ruin
753
- his every chance of success at a university, and if he goes out into the
754
- world as a practicing physician, he will find himself in a society which
755
- does not understand his aims, which regards him with suspicion and
756
- hostility, and which turns loose upon him all the malicious spirits
757
- which lurk within it.
758
- - :title: Grimms' Fairy Tales
759
- :authors:
760
- - :last_name: Grimm
761
- :first_name: Jacob
762
- - :last_name: Grimm
763
- :first_name: Wilhelm
764
- :downloads: 25050
765
- :content: |
766
- A certain king had a beautiful garden, and in the garden stood a tree
767
- which bore golden apples. These apples were always counted, and about
768
- the time when they began to grow ripe it was found that every night one
769
- of them was gone. The king became very angry at this, and ordered the
770
- gardener to keep watch all night under the tree. The gardener set his
771
- eldest son to watch; but about twelve o'clock he fell asleep, and in
772
- the morning another of the apples was missing. Then the second son was
773
- ordered to watch; and at midnight he too fell asleep, and in the morning
774
- another apple was gone. Then the third son offered to keep watch; but
775
- the gardener at first would not let him, for fear some harm should come
776
- to him: however, at last he consented, and the young man laid himself
777
- under the tree to watch. As the clock struck twelve he heard a rustling
778
- noise in the air, and a bird came flying that was of pure gold; and as
779
- it was snapping at one of the apples with its beak, the gardener's son
780
- jumped up and shot an arrow at it. But the arrow did the bird no harm;
781
- only it dropped a golden feather from its tail, and then flew away.
782
- The golden feather was brought to the king in the morning, and all the
783
- council was called together. Everyone agreed that it was worth more than
784
- all the wealth of the kingdom: but the king said, 'One feather is of no
785
- use to me, I must have the whole bird.'
786
-
787
- - :title: An English Grammar
788
- :authors:
789
- - :last_name: Baskervill
790
- :first_name: William Malone
791
- - :last_name: Sewell
792
- :first_name: James Witt
793
- :downloads: 1211
794
- :category: Linguistics
795
- :content: |
796
- Of making many English grammars there is no end; nor should there be
797
- till theoretical scholarship and actual practice are more happily
798
- wedded. In this field much valuable work has already been
799
- accomplished; but it has been done largely by workers accustomed to
800
- take the scholar's point of view, and their writings are addressed
801
- rather to trained minds than to immature learners. To find an advanced
802
- grammar unencumbered with hard words, abstruse thoughts, and difficult
803
- principles, is not altogether an easy matter. These things enhance the
804
- difficulty which an ordinary youth experiences in grasping and
805
- assimilating the facts of grammar, and create a distaste for the
806
- study. It is therefore the leading object of this book to be both as
807
- scholarly and as practical as possible. In it there is an attempt to
808
- present grammatical facts as simply, and to lead the student to
809
- assimilate them as thoroughly, as possible, and at the same time to do
810
- away with confusing difficulties as far as may be.
811
- DATA
812
-
813
- [Book, Author, Authorship, Category].each { |model| model.delete_all }
814
-
815
- books.to_ruby.each do |b|
816
- book = Book.create \
817
- title: b[:title],
818
- downloads: b[:downloads],
819
- content: b[:content]
820
-
821
- b[:authors].each do |a|
822
- author = Author.where(first_name: a[:first_name], last_name: a[:last_name]).first_or_create
823
- book.authors << author
824
- end
134
+ puts
135
+ say_status "Model", "Adding the `abstract` column to Article...\n", :yellow
136
+ puts '-'*80, ''
137
+
138
+ generate :migration, "AddColumnsToArticle abstract:text url:string shares:integer"
139
+ rake "db:migrate"
825
140
 
826
- category = Category.where(title: b[:category]).first_or_create
827
- book.category = category
141
+ git add: "db/"
142
+ git commit: "-m 'Added additional columns to Article'"
143
+
144
+ # ----- Move the model integration into a concern -------------------------------------------------
828
145
 
829
- book.save
146
+ puts
147
+ say_status "Model", "Refactoring the model integration...\n", :yellow
148
+ puts '-'*80, ''; sleep 0.25
149
+
150
+ remove_file 'app/models/article.rb'
151
+ create_file 'app/models/article.rb', <<-CODE
152
+ class Article < ActiveRecord::Base
153
+ include Searchable
830
154
  end
831
155
  CODE
832
156
 
833
- git :add => '.'
834
- git :commit => "-m 'Added data model and seed script (books, categories, authors)'"
157
+ # copy_file File.expand_path('../searchable.rb', __FILE__), 'app/models/concerns/searchable.rb'
158
+ get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/searchable.rb',
159
+ 'app/models/concerns/searchable.rb'
835
160
 
836
- # === TODO: ===
837
- #
838
- # * Update views (show authors, category name, bootstrap)
839
- # <table class="table table-hover">
840
- # class: 'btn btn-default btn-xs'
841
- # class: 'btn btn-primary btn-xs', style: 'color: #fff'
842
- # <td><%= book.authors.map(&:full_name).to_sentence %></td>
843
- # <td><%= book.category.try(:title) || 'n/a' %></td>
844
- # Update controller (fight n+1)
845
- # @books = Book.includes(:authors, :category)
846
- #
161
+ insert_into_file "app/models/article.rb", after: "ActiveRecord::Base" do
162
+ <<-CODE
847
163
 
848
- # ----- Add search support into Book model ---------------------------------------------------------
164
+ has_and_belongs_to_many :categories, after_add: [ lambda { |a,c| Indexer.perform_async(:update, a.class.to_s, a.id) } ],
165
+ after_remove: [ lambda { |a,c| Indexer.perform_async(:update, a.class.to_s, a.id) } ]
166
+ has_many :authorships
167
+ has_many :authors, through: :authorships
168
+ has_many :comments
849
169
 
850
- insert_into_file "app/models/book.rb", :before => "end" do
851
- <<-CODE
170
+ CODE
171
+ end
172
+
173
+ git add: "app/models/"
174
+ git commit: "-m 'Refactored the Elasticsearch integration into a concern\n\nSee:\n\n* http://37signals.com/svn/posts/3372-put-chubby-models-on-a-diet-with-concerns\n* http://joshsymonds.com/blog/2012/10/25/rails-concerns-v-searchable-with-elasticsearch/'"
175
+
176
+ # ----- Add Sidekiq indexer -----------------------------------------------------------------------
177
+
178
+ puts
179
+ say_status "Application", "Adding Sidekiq worker for updating the index...\n", :yellow
180
+ puts '-'*80, ''; sleep 0.25
181
+
182
+ gem "sidekiq"
183
+
184
+ run "bundle install"
185
+
186
+ # copy_file File.expand_path('../indexer.rb', __FILE__), 'app/workers/indexer.rb'
187
+ get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/indexer.rb',
188
+ 'app/workers/indexer.rb'
189
+
190
+ git add: "Gemfile* app/workers/"
191
+ git commit: "-m 'Added a Sidekiq indexer\n\nRun:\n\n $ bundle exec sidekiq --queue elasticsearch --verbose\n\nSee http://sidekiq.org'"
192
+
193
+ # ----- Add SearchController -----------------------------------------------------------------------
194
+
195
+ puts
196
+ say_status "Controllers", "Adding SearchController...\n", :yellow
197
+ puts '-'*80, ''; sleep 0.25
198
+
199
+ create_file 'app/controllers/search_controller.rb' do
200
+ <<-CODE.gsub(/^ /, '')
201
+ class SearchController < ApplicationController
202
+ respond_to :json, :html
203
+
204
+ def index
205
+ options = {
206
+ category: params[:c],
207
+ author: params[:a],
208
+ published_week: params[:w],
209
+ published_day: params[:d],
210
+ sort: params[:s],
211
+ comments: params[:comments]
212
+ }
213
+ @articles = Article.search(params[:q], options).page(params[:page]).results
214
+
215
+ respond_with @articles
216
+ end
217
+
218
+ end
852
219
 
853
- include Searchable
854
220
  CODE
855
221
  end
856
222
 
857
- git :add => 'app/models/book.rb'
858
- git :commit => "-m 'Added search support into the Book model'"
223
+ route "get '/search', to: 'search#index', as: 'search'"
224
+ gsub_file 'config/routes.rb', %r{root to: 'articles#index'$}, "root to: 'search#index'"
859
225
 
860
- # === TODO: ===
861
- #
862
- # * Create search action or controller
863
- # @books = Book.search(params[:q]).records.includes(:authors, :category)
864
- # * Create view
226
+ # copy_file File.expand_path('../index.html.erb', __FILE__), 'app/views/search/index.html.erb'
227
+ get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/index.html.erb',
228
+ 'app/views/search/index.html.erb'
229
+
230
+ # copy_file File.expand_path('../search.css', __FILE__), 'app/assets/stylesheets/search.css'
231
+ get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/search.css',
232
+ 'app/assets/stylesheets/search.css'
233
+
234
+ git add: "app/controllers/ config/routes.rb"
235
+ git add: "app/views/search/ app/assets/stylesheets/search.css"
236
+ git commit: "-m 'Added SearchController#index'"
237
+
238
+ # ----- Add initializer ---------------------------------------------------------------------------
239
+
240
+ puts
241
+ say_status "Application", "Adding Elasticsearch configuration in an initializer...\n", :yellow
242
+ puts '-'*80, ''; sleep 0.5
243
+
244
+ create_file 'config/initializers/elasticsearch.rb', <<-CODE
245
+ # Connect to specific Elasticsearch cluster
246
+ ELASTICSEARCH_URL = ENV['ELASTICSEARCH_URL'] || 'http://localhost:9200'
247
+
248
+ Elasticsearch::Model.client = Elasticsearch::Client.new host: ELASTICSEARCH_URL
249
+
250
+ # Print Curl-formatted traces in development into a file
865
251
  #
252
+ if Rails.env.development?
253
+ tracer = ActiveSupport::Logger.new('log/elasticsearch.log')
254
+ tracer.level = Logger::DEBUG
255
+ end
866
256
 
867
- # ----- Insert seed data into the database ---------------------------------------------------------
257
+ Elasticsearch::Model.client.transport.tracer = tracer
258
+ CODE
259
+
260
+ git add: "config/initializers"
261
+ git commit: "-m 'Added Rails initializer with Elasticsearch configuration'"
262
+
263
+ # ----- Add Rake tasks ----------------------------------------------------------------------------
868
264
 
869
265
  puts
870
- say_status "Database", "Seeding the database with data...", :yellow
871
- puts '-'*80, ''; sleep 0.25
266
+ say_status "Application", "Adding Elasticsearch Rake tasks...\n", :yellow
267
+ puts '-'*80, ''; sleep 0.5
268
+
269
+ create_file 'lib/tasks/elasticsearch.rake', <<-CODE
270
+ require 'elasticsearch/rails/tasks/import'
271
+ CODE
872
272
 
873
- rake "db:seed"
273
+ git add: "lib/tasks"
274
+ git commit: "-m 'Added Rake tasks for Elasticsearch'"
874
275
 
875
- # ----- Import data into Elasticsearch ------------------------------------------------------------
276
+ # ----- Insert and index data ---------------------------------------------------------------------
876
277
 
877
278
  puts
878
- say_status "Index", "Indexing the database...", :yellow
279
+ say_status "Database", "Re-creating the database with data and importing into Elasticsearch...", :yellow
879
280
  puts '-'*80, ''; sleep 0.25
880
281
 
881
- # rake "environment elasticsearch:import:model CLASS='Article' FORCE=true"
882
- run "rails runner 'Book.__elasticsearch__.client.indices.delete index: Book.__elasticsearch__.index_name rescue nil; Book.__elasticsearch__.client.indices.create index: Book.__elasticsearch__.index_name; Book.__elasticsearch__.import'"
282
+ # copy_file File.expand_path('../articles.yml.gz', __FILE__), 'db/articles.yml.gz'
283
+ get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/articles.yml.gz',
284
+ 'db/articles.yml.gz'
285
+
286
+ remove_file 'db/seeds.rb'
287
+ # copy_file File.expand_path('../seeds.rb', __FILE__), 'db/seeds.rb'
288
+ get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/seeds.rb',
289
+ 'db/seeds.rb'
290
+
291
+ rake "db:reset"
292
+ rake "environment elasticsearch:import:model CLASS='Article' BATCH=100 FORCE=y"
293
+
294
+ git add: "db/seeds.rb db/articles.yml.gz"
295
+ git commit: "-m 'Added a seed script and source data'"
883
296
 
884
297
  # ----- Print Git log -----------------------------------------------------------------------------
885
298
 
@@ -887,24 +300,26 @@ puts
887
300
  say_status "Git", "Details about the application:", :yellow
888
301
  puts '-'*80, ''
889
302
 
890
- git :tag => "complex"
891
- git :log => "--reverse --oneline HEAD...pretty"
303
+ git tag: "expert"
304
+ git log: "--reverse --oneline HEAD...pretty"
892
305
 
893
306
  # ----- Start the application ---------------------------------------------------------------------
894
307
 
895
- require 'net/http'
896
- if (begin; Net::HTTP.get(URI('http://localhost:3000')); rescue Errno::ECONNREFUSED; false; rescue Exception; true; end)
897
- puts "\n"
898
- say_status "ERROR", "Some other application is running on port 3000!\n", :red
899
- puts '-'*80
308
+ unless ENV['RAILS_NO_SERVER_START']
309
+ require 'net/http'
310
+ if (begin; Net::HTTP.get(URI('http://localhost:3000')); rescue Errno::ECONNREFUSED; false; rescue Exception; true; end)
311
+ puts "\n"
312
+ say_status "ERROR", "Some other application is running on port 3000!\n", :red
313
+ puts '-'*80
900
314
 
901
- port = ask("Please provide free port:", :bold)
902
- else
903
- port = '3000'
904
- end
315
+ port = ask("Please provide free port:", :bold)
316
+ else
317
+ port = '3000'
318
+ end
905
319
 
906
- puts "", "="*80
907
- say_status "DONE", "\e[1mStarting the application. Open http://localhost:#{port}\e[0m", :yellow
908
- puts "="*80, ""
320
+ puts "", "="*80
321
+ say_status "DONE", "\e[1mStarting the application. Open http://localhost:#{port}\e[0m", :yellow
322
+ puts "="*80, ""
909
323
 
910
- run "rails server --port=#{port}"
324
+ run "rails server --port=#{port}"
325
+ end