lucid_works 0.3.9 → 0.4.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +33 -3
- data/config/locales/en.yml +21 -12
- data/lib/lucid_works.rb +10 -0
- data/lib/lucid_works/associations.rb +14 -12
- data/lib/lucid_works/base.rb +13 -13
- data/lib/lucid_works/collection.rb +65 -5
- data/lib/lucid_works/collection/activity.rb +33 -0
- data/lib/lucid_works/collection/activity/history.rb +20 -0
- data/lib/lucid_works/collection/activity/status.rb +14 -0
- data/lib/lucid_works/collection/settings.rb +28 -8
- data/lib/lucid_works/crawler.rb +3 -3
- data/lib/lucid_works/datasource.rb +29 -3
- data/lib/lucid_works/datasource/job.rb +9 -0
- data/lib/lucid_works/datasource/status.rb +6 -11
- data/lib/lucid_works/patch_time.rb +13 -0
- data/lib/lucid_works/schema.rb +36 -8
- data/lib/lucid_works/utils.rb +22 -0
- data/lib/lucid_works/version.rb +1 -1
- data/lucid_works.gemspec +2 -0
- data/spec/lib/lucid_works/associations_spec.rb +12 -1
- data/spec/lib/lucid_works/base_spec.rb +26 -10
- data/spec/lib/lucid_works/collection/activity/history_spec.rb +33 -0
- data/spec/lib/lucid_works/collection/activity/status_spec.rb +20 -0
- data/spec/lib/lucid_works/collection/activity_spec.rb +88 -0
- data/spec/lib/lucid_works/collection/prime_activities_spec.rb +86 -0
- data/spec/lib/lucid_works/collection_spec.rb +140 -1
- data/spec/lib/lucid_works/datasource/history_spec.rb +11 -7
- data/spec/lib/lucid_works/datasource/status_spec.rb +64 -32
- data/spec/lib/lucid_works/datasource_spec.rb +48 -13
- data/spec/lib/lucid_works/schema_spec.rb +56 -4
- data/spec/lib/lucid_works/utils_spec.rb +62 -0
- data/spec/spec_helper.rb +17 -14
- metadata +41 -3
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'lucid_works/field'
|
2
|
+
|
1
3
|
module LucidWorks
|
2
4
|
class Collection
|
3
5
|
|
@@ -5,18 +7,36 @@ module LucidWorks
|
|
5
7
|
self.singleton = true
|
6
8
|
belongs_to :collection
|
7
9
|
|
8
|
-
DEDUP_OPTIONS
|
10
|
+
DEDUP_OPTIONS = %w{ off overwrite tag }
|
11
|
+
QUERY_PARSERS = %w{ lucid dismax edismax lucene }
|
12
|
+
DEFAULT_SORTS = %w{ relevance date random }
|
13
|
+
FEEDBACK_EMPHASIS = %w{ relevancy recall }
|
9
14
|
|
10
15
|
schema do
|
11
|
-
|
12
|
-
|
13
|
-
:type => :string
|
16
|
+
# Indexing Settings
|
17
|
+
attribute :unknown_type_handling, :string, :values => LucidWorks::Field::TYPES
|
14
18
|
attribute :de_duplication, :string, :values => DEDUP_OPTIONS
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
+
attribute :index_time_stopwords, :boolean
|
20
|
+
|
21
|
+
# Querying Settings
|
22
|
+
attribute :unsupervised_feedback_emphasis, :string, :values => FEEDBACK_EMPHASIS
|
23
|
+
attribute :default_sort, :string, :values => DEFAULT_SORTS
|
24
|
+
attribute :query_parser, :string, :values => QUERY_PARSERS
|
25
|
+
attributes :spellcheck, :display_facets, :unsupervised_feedback, :query_time_stopwords,
|
26
|
+
:auto_complete, :boost_recent, :show_similar, :query_time_synonyms,
|
27
|
+
:type => :boolean
|
28
|
+
attributes :stopword_list, :boosts, :synonym_list # Arrays
|
29
|
+
|
30
|
+
# Click Settings
|
31
|
+
attributes :click_boost_field, :click_boost_data, :type => :string
|
32
|
+
attribute :click_enabled, :boolean
|
33
|
+
|
34
|
+
# Other Settings
|
35
|
+
attribute :ssl, :boolean
|
19
36
|
attribute :elevations # Hash
|
37
|
+
|
38
|
+
# Distrubuted Search Settings
|
39
|
+
attributes :search_server_list, :update_server_list # Arrays
|
20
40
|
end
|
21
41
|
end
|
22
42
|
end
|
data/lib/lucid_works/crawler.rb
CHANGED
@@ -4,12 +4,12 @@ module LucidWorks
|
|
4
4
|
belongs_to :collection
|
5
5
|
has_many :histories, :class_name => :history
|
6
6
|
has_one :status, :schedule, :crawldata
|
7
|
-
has_one :index, :has_content => false
|
7
|
+
has_one :index, :job, :has_content => false
|
8
8
|
|
9
9
|
schema do
|
10
10
|
# common
|
11
11
|
attributes :name, :type, :crawler
|
12
|
-
attributes :crawl_depth, :max_bytes, :type => :integer
|
12
|
+
attributes :crawl_depth, :max_bytes, :max_docs, :type => :integer
|
13
13
|
attribute :include_paths
|
14
14
|
attribute :exclude_paths
|
15
15
|
attribute :mapping # Hash
|
@@ -20,6 +20,9 @@ module LucidWorks
|
|
20
20
|
# file
|
21
21
|
attribute :path
|
22
22
|
attribute :follow_links, :boolean
|
23
|
+
|
24
|
+
# new un-evaluated
|
25
|
+
# attributes :commitWithin
|
23
26
|
end
|
24
27
|
|
25
28
|
validates_presence_of :type, :crawler, :name, :crawl_depth
|
@@ -28,7 +31,7 @@ module LucidWorks
|
|
28
31
|
|
29
32
|
before_save :remove_blank_max_bytes
|
30
33
|
|
31
|
-
TYPES = %w{ file web solrxml jdbc sharepoint }
|
34
|
+
TYPES = %w{ external file lwelogs web solrxml jdbc sharepoint }
|
32
35
|
BOUNDS = %w{ tree none }
|
33
36
|
CRAWLERS = {
|
34
37
|
# Later we may change these to be arrays if we decide to support more than one choice
|
@@ -45,6 +48,29 @@ module LucidWorks
|
|
45
48
|
index.destroy
|
46
49
|
end
|
47
50
|
|
51
|
+
def editable?
|
52
|
+
# lwelogs is not editable
|
53
|
+
type != 'lwelogs'
|
54
|
+
end
|
55
|
+
|
56
|
+
def destroyable?
|
57
|
+
# Don't let user destroy 'lwelogs'
|
58
|
+
type != 'lwelogs'
|
59
|
+
end
|
60
|
+
|
61
|
+
def crawlable?
|
62
|
+
# Don't let user schedule crawl of 'lwelogs'
|
63
|
+
!%w{ external lwelogs }.include?(type)
|
64
|
+
end
|
65
|
+
|
66
|
+
def start_crawl!
|
67
|
+
job.save
|
68
|
+
end
|
69
|
+
|
70
|
+
def stop_crawl!
|
71
|
+
job.destroy
|
72
|
+
end
|
73
|
+
|
48
74
|
def t_type
|
49
75
|
I18n.t(type, :scope => 'activemodel.models.lucid_works.datasource.type')
|
50
76
|
end
|
@@ -5,15 +5,16 @@ module LucidWorks
|
|
5
5
|
self.singleton = true
|
6
6
|
belongs_to :datasource
|
7
7
|
|
8
|
-
schema do
|
9
|
-
attributes :crawlStarted, :crawlState, :crawlStopped, :jobId
|
10
|
-
attributes :numUnchanged, :numUpdated, :numNew, :numFailed, :numDeleted, :type => :integer
|
11
|
-
end
|
12
|
-
|
13
8
|
STOPPED_STATES = %w{ IDLE STOPPED ABORTED EXCEPTION FINISHED }
|
14
9
|
POST_PROCESSING_STATES = %w{ STOPPING ABORTING }
|
15
10
|
CRAWLSTATES = STOPPED_STATES + [ 'RUNNING' ] + POST_PROCESSING_STATES
|
16
11
|
|
12
|
+
schema do
|
13
|
+
attribute :crawlState, :string, :values => CRAWLSTATES
|
14
|
+
attributes :crawlStarted, :crawlStopped, :jobId
|
15
|
+
attributes :numUnchanged, :numUpdated, :numNew, :numFailed, :numDeleted, :numTotal, :type => :integer
|
16
|
+
end
|
17
|
+
|
17
18
|
# Create predicate methods for all the crawl states
|
18
19
|
CRAWLSTATES.each do |state|
|
19
20
|
method_name = state.downcase + "?"
|
@@ -36,12 +37,6 @@ module LucidWorks
|
|
36
37
|
numUpdated + numNew + numUnchanged
|
37
38
|
end
|
38
39
|
|
39
|
-
def t_crawl_state
|
40
|
-
I18n.translate(crawlState.downcase,
|
41
|
-
:scope => 'activemodel.models.lucid_works.datasource.status.crawl_state',
|
42
|
-
:default => crawlState)
|
43
|
-
end
|
44
|
-
|
45
40
|
def crawl_started
|
46
41
|
Time.iso8601 crawlStarted
|
47
42
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
class Time
|
4
|
+
class << self
|
5
|
+
# Ruby's 'Time.is08601 can't handle timezone offsets expressed as +nnnn.
|
6
|
+
# It prefers +nn:nn. Morph the former to the latter.
|
7
|
+
def iso8601_with_support_for_timezones_without_colons(datetime_string)
|
8
|
+
iso8601_without_support_for_timezones_without_colons(datetime_string.gsub /([+-])(\d\d)(\d\d)$/, '\1\2:\3')
|
9
|
+
end
|
10
|
+
|
11
|
+
alias_method_chain :iso8601, :support_for_timezones_without_colons
|
12
|
+
end
|
13
|
+
end
|
data/lib/lucid_works/schema.rb
CHANGED
@@ -1,10 +1,30 @@
|
|
1
1
|
module LucidWorks
|
2
2
|
|
3
|
+
# Specify an attributes for a model.
|
3
4
|
class Schema < ActiveSupport::HashWithIndifferentAccess
|
4
5
|
|
5
|
-
|
6
|
+
def initialize
|
7
|
+
@primary_key = :id
|
8
|
+
@dynamic_attributes = true
|
9
|
+
end
|
10
|
+
|
11
|
+
def primary_key(key=nil)
|
12
|
+
@primary_key = key.to_sym if key
|
13
|
+
@primary_key
|
14
|
+
end
|
15
|
+
|
16
|
+
# Specify whether attributes unrecognized during retrieval should raise an error (false)
|
17
|
+
# or cause a new attribute to be added to the schema (true) [default].
|
18
|
+
#
|
19
|
+
def dynamic_attributes(on=nil)
|
20
|
+
@dynamic_attributes = !!on unless on.nil?
|
21
|
+
@dynamic_attributes
|
22
|
+
end
|
23
|
+
|
24
|
+
alias :dynamic_attributes? :dynamic_attributes
|
6
25
|
|
7
26
|
def attribute(name, type=:string, options={})
|
27
|
+
primary_key name if options.delete(:primary_key)
|
8
28
|
self[name] = options.merge(:type => type)
|
9
29
|
end
|
10
30
|
|
@@ -13,7 +33,7 @@ module LucidWorks
|
|
13
33
|
# schema do
|
14
34
|
# attributes :first_name, :last_name, :type => :string
|
15
35
|
# end
|
16
|
-
|
36
|
+
#
|
17
37
|
def attributes(*attributes_and_options)
|
18
38
|
options = attributes_and_options.last.is_a?(Hash) ? attributes_and_options.pop : {}
|
19
39
|
attributes = attributes_and_options
|
@@ -26,6 +46,10 @@ module LucidWorks
|
|
26
46
|
has_key? sanitize_identifier(name)
|
27
47
|
end
|
28
48
|
|
49
|
+
def attrs_to_omit_during_update
|
50
|
+
select { |k,v| v['omit_during_update'] == true }.keys
|
51
|
+
end
|
52
|
+
|
29
53
|
# Used for classes that have no predefined schema.
|
30
54
|
# When the class is retrieved.
|
31
55
|
def add_attribute(klass, name, type=:string) # :nodoc:
|
@@ -47,10 +71,6 @@ module LucidWorks
|
|
47
71
|
def #{attribute} # def foo
|
48
72
|
@attributes[:#{attribute}] # @attributes[:foo]
|
49
73
|
end # end
|
50
|
-
|
51
|
-
def #{attribute}=(new_value) # def foo=(new_value)
|
52
|
-
@attributes[:#{attribute}] = new_value # @attributes[:foo] = new_value
|
53
|
-
end # end
|
54
74
|
EOF
|
55
75
|
|
56
76
|
if self[attribute][:type] == :boolean
|
@@ -58,12 +78,20 @@ module LucidWorks
|
|
58
78
|
def #{attribute}? # def foo?
|
59
79
|
@attributes[:#{attribute}] # @attributes[:foo]
|
60
80
|
end # end
|
81
|
+
|
82
|
+
def #{attribute}=(new_value) # def foo=(new_value)
|
83
|
+
@attributes[:#{attribute}] = to_bool(new_value) # @attributes[:foo] = to_bool(new_value)
|
84
|
+
end # end
|
85
|
+
EOF
|
86
|
+
else
|
87
|
+
klass.class_eval <<-EOF, __FILE__, __LINE__+1
|
88
|
+
def #{attribute}=(new_value) # def foo=(new_value)
|
89
|
+
@attributes[:#{attribute}] = new_value # @attributes[:foo] = new_value
|
90
|
+
end # end
|
61
91
|
EOF
|
62
92
|
end
|
63
93
|
end
|
64
94
|
|
65
|
-
private
|
66
|
-
|
67
95
|
# Change any characters illegal for an identifier to _
|
68
96
|
def sanitize_identifier(identifier) # :nodoc:
|
69
97
|
identifier.to_s.gsub(/[^\w]/, '_').to_sym
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module LucidWorks
|
2
|
+
module Utils
|
3
|
+
module BoolConverter
|
4
|
+
TRUE_VALUES = %w(t true 1 yes)
|
5
|
+
FALSE_VALUES = %w(f false 0 no)
|
6
|
+
|
7
|
+
def to_bool(thing)
|
8
|
+
if thing.kind_of?(TrueClass) || thing.kind_of?(FalseClass)
|
9
|
+
thing
|
10
|
+
elsif thing.kind_of?(String)
|
11
|
+
raise "Sorry, I can't to_bool \"#{thing}\"" unless (TRUE_VALUES + FALSE_VALUES).include?(thing.downcase)
|
12
|
+
TRUE_VALUES.include?(thing.downcase)
|
13
|
+
elsif thing.kind_of?(Integer)
|
14
|
+
raise "Sorry, I can't to_bool #{thing}" unless [0, 1].include?(thing)
|
15
|
+
thing == 1
|
16
|
+
else
|
17
|
+
raise "Sorry, I can't to_bool things of class #{thing.class.name}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/lucid_works/version.rb
CHANGED
data/lucid_works.gemspec
CHANGED
@@ -30,9 +30,20 @@ describe LucidWorks::Associations do
|
|
30
30
|
describe ".has_one" do
|
31
31
|
context "without content" do
|
32
32
|
describe "#<child>" do
|
33
|
+
it "should call child! the first time then return the cached value thereafter" do
|
34
|
+
mock_launch_party = double('launch_party')
|
35
|
+
LaunchParty.should_receive(:new).once.and_return(mock_launch_party)
|
36
|
+
|
37
|
+
@blog.launch_party.should == mock_launch_party
|
38
|
+
@blog.launch_party.should == mock_launch_party
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#<child!>" do
|
33
43
|
it "should build a new model, and not call REST API to retrieve" do
|
34
44
|
LaunchParty.should_not_receive(:find)
|
35
|
-
|
45
|
+
|
46
|
+
launch_party = @blog.launch_party!
|
36
47
|
|
37
48
|
launch_party.should be_a(LaunchParty)
|
38
49
|
launch_party.should be_persisted # All singletons are always persisted
|
@@ -38,10 +38,6 @@ describe LucidWorks::Base do
|
|
38
38
|
|
39
39
|
describe ".schema" do
|
40
40
|
context "for a class with a schema" do
|
41
|
-
it "should set has_schema" do
|
42
|
-
WidgetWithSchema.has_schema.should be_true
|
43
|
-
end
|
44
|
-
|
45
41
|
it "should have accessors for the attributes defined in the schema" do
|
46
42
|
[:name, :name=, :frooble, :frooble=].each do |method|
|
47
43
|
WidgetWithSchema.new(:parent => @server).should respond_to(method)
|
@@ -66,10 +62,7 @@ describe LucidWorks::Base do
|
|
66
62
|
end
|
67
63
|
end
|
68
64
|
|
69
|
-
context "for a class
|
70
|
-
it "should return false for has_schema" do
|
71
|
-
WidgetWithoutSchema.has_schema.should be_false
|
72
|
-
end
|
65
|
+
context "for a class with default schema (i.e. dynamic_attributes == true)" do
|
73
66
|
|
74
67
|
it "should create accessors upon retrieval" do
|
75
68
|
widget = WidgetWithoutSchema.new(:parent => @server)
|
@@ -354,7 +347,7 @@ describe LucidWorks::Base do
|
|
354
347
|
it "should create an array of arrays suitable for a form select" do
|
355
348
|
# Use Collection::Settings because we know de_duplication as translations
|
356
349
|
LucidWorks::Collection::Settings.to_select(:de_duplication).should ==
|
357
|
-
[['
|
350
|
+
[['Off', 'off'], ['Overwrite', 'overwrite'], ['Tag', 'tag']]
|
358
351
|
end
|
359
352
|
end
|
360
353
|
end
|
@@ -472,6 +465,27 @@ describe LucidWorks::Base do
|
|
472
465
|
@widget.save
|
473
466
|
end
|
474
467
|
end
|
468
|
+
|
469
|
+
context "for a persisted instance of a model with an attribute marked :omit_during_update" do
|
470
|
+
before do
|
471
|
+
class WidgetWithOmit < LucidWorks::Base
|
472
|
+
schema do
|
473
|
+
attribute :foo, :string
|
474
|
+
attribute :bar, :string, :omit_during_update => true
|
475
|
+
end
|
476
|
+
end
|
477
|
+
@widget_attrs = { :foo => 'frooble', :bar => 'barfalicious' }
|
478
|
+
@widget_with_omit = WidgetWithOmit.new(@widget_attrs.merge :id => 1234, :parent => @server, :persisted => true)
|
479
|
+
end
|
480
|
+
|
481
|
+
it "should omit said attribute when performing the save" do
|
482
|
+
expected_json = @widget_attrs.reject { |k,v| k.to_sym == :bar }.to_json
|
483
|
+
correct_url = "#{@fake_server_uri}/widget_with_omits/1234"
|
484
|
+
RestClient.should_receive(:put).with(correct_url, expected_json, :content_type => :json)
|
485
|
+
|
486
|
+
@widget_with_omit.save
|
487
|
+
end
|
488
|
+
end
|
475
489
|
end
|
476
490
|
|
477
491
|
describe "#update_attributes" do
|
@@ -507,7 +521,9 @@ describe LucidWorks::Base do
|
|
507
521
|
describe "for a model with primary key other than 'id'" do
|
508
522
|
before :all do
|
509
523
|
class NamedWidget < LucidWorks::Base
|
510
|
-
|
524
|
+
schema do
|
525
|
+
primary_key :name
|
526
|
+
end
|
511
527
|
end
|
512
528
|
NAMED_WIDGET1_JSON = '{"name":"widget1","size":"small"}'
|
513
529
|
NAMED_WIDGET2_JSON = '{"name":"widget2","size":"medium"}'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
|
4
|
+
describe LucidWorks::Collection::Activity::History do
|
5
|
+
before :all do
|
6
|
+
@server = connect_to_live_server
|
7
|
+
@server.reset_collections!
|
8
|
+
@collection = @server.collections!.first
|
9
|
+
@activity = @collection.build_activity(:type => 'optimize', :start_time => 0, :active => true)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "after running" do
|
13
|
+
before :all do
|
14
|
+
@activity.save.should be_true
|
15
|
+
sleep 1
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should have a history array with one element" do
|
19
|
+
histories = @activity.histories
|
20
|
+
histories.count.should == 1
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should subtract crawlStarted form crawlStopped and return the difference in seconds" do
|
24
|
+
include ActiveSupport::Duration
|
25
|
+
|
26
|
+
history = LucidWorks::Collection::Activity::History.new(:parent => @activity)
|
27
|
+
now = Time.now
|
28
|
+
history.stub(:activity_started) { now.advance(:seconds => -15) }
|
29
|
+
history.stub(:activity_finished) { now.advance(:seconds => -10) }
|
30
|
+
history.duration.should == 5.seconds
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LucidWorks::Collection::Activity::Status do
|
4
|
+
before :all do
|
5
|
+
@server = connect_to_live_server
|
6
|
+
@server.reset_collections!
|
7
|
+
@collection = @server.collections!.first
|
8
|
+
@activity = @collection.create_activity(:type => 'optimize', :start_time => 8600)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "find" do
|
12
|
+
it "should retrieve status" do
|
13
|
+
status = @activity.status
|
14
|
+
status.should be_a LucidWorks::Collection::Activity::Status
|
15
|
+
|
16
|
+
status.running.should be_false
|
17
|
+
status.type.should == 'optimize'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|