lucid_works 0.6.18 → 0.6.19

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  module LucidWorks
2
- class Collection::Activity
2
+ class Activity
3
3
  class History < Base
4
4
  belongs_to :activity
5
5
  self.collection_name = 'history' # i.e. not the plural 'histories'
@@ -1,12 +1,12 @@
1
1
  module LucidWorks
2
- class Collection::Activity
2
+ class Activity
3
3
  class Status < Base
4
4
  self.singleton = true
5
5
  belongs_to :activity
6
6
 
7
7
  schema do
8
8
  attribute :running, :boolean
9
- attribute :type, :string, :values => LucidWorks::Collection::Activity::TYPES
9
+ attribute :type, :string, :values => LucidWorks::Activity::TYPES
10
10
  end
11
11
 
12
12
  end
@@ -0,0 +1,190 @@
1
+ require 'active_support/core_ext/numeric/time.rb'
2
+ module LucidWorks
3
+
4
+ class Activity < Base
5
+ TYPES = %w{ optimize spelling click autocomplete}
6
+
7
+ # Unlike Datasource schedules, the API allows multiples of these
8
+ # So, to be honest with gem users, we can't really say this:
9
+ # self.singleton = true
10
+ belongs_to :collection
11
+ has_many :histories, :class_name => :history
12
+ has_one :status
13
+
14
+ schema do
15
+ attribute :period
16
+ attribute :start_time, :iso8601
17
+ attribute :active, :boolean
18
+ attribute :type, :string, :values => TYPES, :omit_during_update => true
19
+ end
20
+
21
+ validates_presence_of :type, :start_time
22
+ validates_numericality_of :period, :allow_blank => true
23
+
24
+ def frequency
25
+ case period
26
+ when 1.weeks.seconds then 'weekly'
27
+ when 1.days.seconds then 'daily'
28
+ when 1.hours.seconds then 'hourly'
29
+ when 0 then nil
30
+ else 'custom'
31
+ end
32
+ end
33
+
34
+ #
35
+ # accepts hourly, daily, weekly, and sets period to respective # of seconds
36
+ #
37
+ def frequency=(frequency)
38
+ self.period = case frequency
39
+ when 'hourly' then 1.hours.seconds
40
+ when 'daily' then 1.days.seconds
41
+ when 'weekly' then 1.weeks.seconds
42
+ else raise "unknown frequency"
43
+ end
44
+ end
45
+
46
+ #
47
+ # predict when action will occur next if active at that time
48
+ #
49
+ def next_start
50
+ return start_time if (now = Time.now) <= start_time
51
+ # require 'ruby-debug'; debugger
52
+ time_since_start = now - start_time
53
+ last_interval_num = (time_since_start / period).to_i
54
+ next_interval_num = if (time_since_start % period) == 0
55
+ # this is sort of a stupid condition b/c time precision is millisecond or less
56
+ # for human purposes we wouldn't care if the result were as though the call
57
+ # happened a millisecond later. But whatever.
58
+ last_interval_num # the next interval *is* the last interval if it is exactly now
59
+ else
60
+ last_interval_num + 1
61
+ end
62
+ start_time + period * next_interval_num
63
+ end
64
+
65
+ #
66
+ # phantom attribute for compiling real start time and frequency from appropriate form data
67
+ # Allows the user to specify a schedule simply with repeat interval (hourly, daily, weekly)
68
+ # and time within the interval to run (e.g 5 past, or Tuesdays at 2:15)
69
+ #
70
+ # We have to figure out when the actual start time will be because we are not asking
71
+ # the user for this. It needs to be:
72
+ # * at the requested time relative to the interval chosen
73
+ # * as soon as possible
74
+ # * in the future
75
+ #
76
+ # This is obvious to humans, but when computing it, you run into the following problem. It
77
+ # happens with all interval sizes, but for the sake of example, we'll use weekly:
78
+ #
79
+ # Problem 1) If today is Thursday, and the user asks for "weekly on Wednesdays," Wednesday has
80
+ # already happened this week. We have to make sure we pick the nearest wednesday that is in
81
+ # the future
82
+ #
83
+ # Problem 2) If today is Tuesday, and the user asks for "weekly on Wednesdays,", the simple solution
84
+ # to problem 1 (start next week instead of this week) causes you to skip this Tuesday, even though
85
+ # it is valid and is what the user would expect
86
+ #
87
+ # The algorith to solve both problems at once is this:
88
+ # * From Time.now, back up to the beginning of the interval even if it is in the past.
89
+ # * Fast forward to the requested siimple start time
90
+ # * If you are still in the past, advance by one interval
91
+ #
92
+ def schedule=(all_attributes)
93
+ # convert to format accepted by Time.advance
94
+ if all_attributes['start']
95
+ all_attributes['start'].to_options!
96
+ all_attributes['start'].each{|k,v| all_attributes['start'][k]=v.to_i}
97
+ end
98
+
99
+ self.active = all_attributes['active'] if all_attributes.keys.include?('active')
100
+
101
+ now = Time.now
102
+ self.frequency = all_attributes['frequency']
103
+ self.start_time =
104
+ case all_attributes['frequency']
105
+ when 'weekly'
106
+ # require 'ruby-debug'; debugger
107
+ start = now.beginning_of_week.advance(all_attributes['start'])
108
+ start < now ? start.advance(:weeks => 1) : start
109
+ when 'daily'
110
+ start = now.beginning_of_day.advance(all_attributes['start'])
111
+ start < now ? start.advance(:days => 1) : start
112
+ when 'hourly'
113
+ start = now.change(:min => 0).advance(all_attributes['start'])
114
+ start < now ? start.advance(:hours => 1) : start
115
+ else
116
+ puts "*** frequency: <#{all_attributes[:frequency]}>"
117
+ raise "unexpected frequency encountered"
118
+ end
119
+ end
120
+
121
+ #
122
+ # convenince method for setting the current value in a view selector
123
+ #
124
+ def hour
125
+ self.start_time.localtime.hour rescue nil
126
+ end
127
+
128
+ #
129
+ # convenince method for setting the current value in a view selector
130
+ #
131
+ def min
132
+ self.start_time.localtime.min rescue nil
133
+ end
134
+
135
+ #
136
+ # convenince method for setting the current value in a view selector
137
+ #
138
+ def day_of_week
139
+ # subract 1 because '%u' returns 1-7, and this is working with zero-indexed ruby arrays
140
+ self.start_time.localtime.strftime('%u').to_i - 1 rescue nil
141
+ end
142
+
143
+ def start_is_more_than_one_period_in_the_future?
144
+ # This works fine with start times that are multiple periods in the past
145
+ # because that gives a negative difference, and period is always >= 0
146
+ (self.start_time - Time.now) > self.period
147
+ end
148
+
149
+ #
150
+ # convenience method for detecting whether schedule can be represented in simple format
151
+ # or should be described as custom (meaning it is beyond the capabilities of the convenience methods)
152
+ #
153
+ def custom?
154
+ return false unless self.start_time
155
+ return true if self.frequency == 'custom'
156
+ return true if self.start_is_more_than_one_period_in_the_future?
157
+ return false
158
+ end
159
+
160
+ #
161
+ # convenience method for setting defaults in a UI that make sense for a user
162
+ #
163
+ def ui_appropriate_defaults!
164
+ if self.start_time.blank? || self.period == 0
165
+ self.active = true
166
+ end
167
+ end
168
+
169
+ def t_type
170
+ I18n.t(type, :scope => 'activemodel.models.lucid_works.collection.activity.type')
171
+ end
172
+
173
+ def start
174
+ self.start_time = 0
175
+ self.active = true
176
+ save
177
+ end
178
+
179
+ private
180
+
181
+ def exact(interval, period)
182
+ if period % (result = 1.send(interval)) == 0
183
+ period / result
184
+ else
185
+ false
186
+ end
187
+ end
188
+
189
+ end
190
+ end
@@ -1,3 +1,3 @@
1
1
  module LucidWorks
2
- VERSION = "0.6.18"
2
+ VERSION = "0.6.19"
3
3
  end
@@ -0,0 +1,60 @@
1
+ module LucidWorks
2
+
3
+ class Synonym
4
+ include ActiveModel::Validations
5
+ include ActiveModel::Conversion
6
+ extend ActiveModel::Naming
7
+ extend SimpleNaming
8
+
9
+ attr_reader :id, :collection, :persisted
10
+ attr_accessor :mapping
11
+
12
+ validates_presence_of :mapping
13
+ validates_each :mapping, :allow_blank => true do |model, attr, value|
14
+ model.errors.add(attr, 'must be a comma-separated list') if value =~ /=>/ || value.split(',').size < 2
15
+ end
16
+
17
+ def initialize(attributes = {})
18
+ @id = attributes[:id]
19
+ @collection = attributes[:collection]
20
+ @mapping = attributes[:mapping]
21
+ @persisted = attributes[:persisted] || false
22
+ end
23
+
24
+ def persisted?
25
+ @persisted
26
+ end
27
+
28
+ def save
29
+ return false unless valid?
30
+ if persisted?
31
+ settings.synonym_list[id] = mapping
32
+ else
33
+ settings.synonym_list << mapping
34
+ @id = settings.synonym_list.length - 1
35
+ end
36
+ settings.save
37
+ @persisted = true
38
+ rescue
39
+ false
40
+ end
41
+
42
+ def update_attributes(attrs_and_values)
43
+ attrs_and_values.each do |attr,value|
44
+ self.send("#{attr}=", value)
45
+ end
46
+ save
47
+ end
48
+
49
+ def destroy
50
+ settings.synonym_list.delete_at(id)
51
+ settings.save
52
+ end
53
+
54
+ private
55
+
56
+ def settings
57
+ collection.settings
58
+ end
59
+ end
60
+ end
data/lib/lucid_works.rb CHANGED
@@ -27,14 +27,12 @@ require 'lucid_works/base'
27
27
  require 'lucid_works/schema'
28
28
 
29
29
  require 'lucid_works/collection'
30
- require 'lucid_works/collection/activity'
31
- require 'lucid_works/collection/activity/status'
32
- require 'lucid_works/collection/activity/history'
33
- #require 'lucid_works/collection/activity/schedule'
34
30
  require 'lucid_works/collection/info'
35
31
  require 'lucid_works/collection/index'
36
32
  require 'lucid_works/collection/settings'
37
- require 'lucid_works/collection/synonym'
33
+ require 'lucid_works/activity'
34
+ require 'lucid_works/activity/status'
35
+ require 'lucid_works/activity/history'
38
36
  require 'lucid_works/crawler'
39
37
  require 'lucid_works/datasource'
40
38
  require 'lucid_works/datasource/index'
@@ -44,6 +42,7 @@ require 'lucid_works/datasource/schedule'
44
42
  require 'lucid_works/datasource/crawldata'
45
43
  require 'lucid_works/datasource/job'
46
44
  require 'lucid_works/field'
45
+ require 'lucid_works/synonym'
47
46
  require 'lucid_works/logs'
48
47
  require 'lucid_works/logs/query'
49
48
  require 'lucid_works/logs/query/summary'
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'active_support/core_ext'
3
3
 
4
- describe LucidWorks::Collection::Activity::History do
4
+ describe LucidWorks::Activity::History do
5
5
  before :all do
6
6
  @server = connect_to_live_server
7
7
  @server.reset_collections!
@@ -23,7 +23,7 @@ describe LucidWorks::Collection::Activity::History do
23
23
  it "should subtract crawlStarted form crawlStopped and return the difference in seconds" do
24
24
  include ActiveSupport::Duration
25
25
 
26
- history = LucidWorks::Collection::Activity::History.new(:parent => @activity)
26
+ history = LucidWorks::Activity::History.new(:parent => @activity)
27
27
  now = Time.now
28
28
  history.stub(:activity_started) { now.advance(:seconds => -15) }
29
29
  history.stub(:activity_finished) { now.advance(:seconds => -10) }
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe LucidWorks::Collection::Activity::Status do
3
+ describe LucidWorks::Activity::Status do
4
4
  before :all do
5
5
  @server = connect_to_live_server
6
6
  @server.reset_collections!
@@ -11,7 +11,7 @@ describe LucidWorks::Collection::Activity::Status do
11
11
  describe "find" do
12
12
  it "should retrieve status" do
13
13
  status = @activity.status
14
- status.should be_a LucidWorks::Collection::Activity::Status
14
+ status.should be_a LucidWorks::Activity::Status
15
15
 
16
16
  status.running.should be_false
17
17
  status.type.should == 'optimize'
@@ -14,7 +14,7 @@ require 'spec_helper'
14
14
  end
15
15
 
16
16
 
17
- describe LucidWorks::Collection::Activity do
17
+ describe LucidWorks::Activity do
18
18
  context "Functionality shared with Datasource scheduling" do
19
19
  before :all do
20
20
  ENV['TZ'] = 'UTC'
@@ -20,13 +20,13 @@ describe "LucidWorks::Collection#prime_activities" do
20
20
  end
21
21
 
22
22
  it "should produce activities of the appropriate type" do
23
- @collection.optimize_activity.should be_a LucidWorks::Collection::Activity
23
+ @collection.optimize_activity.should be_a LucidWorks::Activity
24
24
  @collection.optimize_activity.type.should == 'optimize'
25
- @collection.spelling_activity.should be_a LucidWorks::Collection::Activity
25
+ @collection.spelling_activity.should be_a LucidWorks::Activity
26
26
  @collection.spelling_activity.type.should == 'spelling'
27
- @collection.click_activity.should be_a LucidWorks::Collection::Activity
27
+ @collection.click_activity.should be_a LucidWorks::Activity
28
28
  @collection.click_activity.type.should == 'click'
29
- @collection.autocomplete_activity.should be_a LucidWorks::Collection::Activity
29
+ @collection.autocomplete_activity.should be_a LucidWorks::Activity
30
30
  @collection.autocomplete_activity.type.should == 'autocomplete'
31
31
  end
32
32
  end
@@ -37,7 +37,7 @@ describe "LucidWorks::Collection#prime_activities" do
37
37
  before :all do
38
38
  @collection = @server.create_collection(:name => 'collection_with_no_activities_2', :parent => @server)
39
39
  spelling_activity = @collection.create_activity(:type => 'spelling', :start_time => 3600, :active => true)
40
- spelling_activity.should be_a LucidWorks::Collection::Activity
40
+ spelling_activity.should be_a LucidWorks::Activity
41
41
  end
42
42
 
43
43
  it "should not create duplicates for existing types" do
@@ -61,13 +61,13 @@ describe "LucidWorks::Collection#prime_activities" do
61
61
 
62
62
  it "should have a virtual attribute for each activity type" do
63
63
  @collection.activities!.count.should == 4
64
- @collection.optimize_activity.should be_a LucidWorks::Collection::Activity
64
+ @collection.optimize_activity.should be_a LucidWorks::Activity
65
65
  @collection.optimize_activity.type.should == 'optimize'
66
- @collection.spelling_activity.should be_a LucidWorks::Collection::Activity
66
+ @collection.spelling_activity.should be_a LucidWorks::Activity
67
67
  @collection.spelling_activity.type.should == 'spelling'
68
- @collection.click_activity.should be_a LucidWorks::Collection::Activity
68
+ @collection.click_activity.should be_a LucidWorks::Activity
69
69
  @collection.click_activity.type.should == 'click'
70
- @collection.autocomplete_activity.should be_a LucidWorks::Collection::Activity
70
+ @collection.autocomplete_activity.should be_a LucidWorks::Activity
71
71
  @collection.autocomplete_activity.type.should == 'autocomplete'
72
72
  end
73
73
 
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
- require 'lucid_works/collection/synonym'
3
2
 
4
- describe LucidWorks::Collection::Synonym do
3
+ describe LucidWorks::Synonym do
5
4
  before do
6
5
  @server = connect_to_live_server.tap {|server| server.reset_collections! }
7
6
  load_collection
@@ -14,15 +13,15 @@ describe LucidWorks::Collection::Synonym do
14
13
 
15
14
  describe "naming support" do
16
15
  it "demodulizes names" do
17
- LucidWorks::Collection::Synonym.model_name.singular.should == "synonym"
18
- LucidWorks::Collection::Synonym.model_name.plural.should == "synonyms"
19
- LucidWorks::Collection::Synonym.model_name.collection.should == "synonyms"
16
+ LucidWorks::Synonym.model_name.singular.should == "synonym"
17
+ LucidWorks::Synonym.model_name.plural.should == "synonyms"
18
+ LucidWorks::Synonym.model_name.collection.should == "synonyms"
20
19
  end
21
20
  end
22
21
 
23
22
  describe "conversion support" do
24
23
  it "can be converted to a key" do
25
- synonym = LucidWorks::Collection::Synonym.new(:collection => @collection, :mapping => "car, auto")
24
+ synonym = LucidWorks::Synonym.new(:collection => @collection, :mapping => "car, auto")
26
25
  synonym.save
27
26
  synonym.to_key.should == [8]
28
27
  end
@@ -30,19 +29,19 @@ describe LucidWorks::Collection::Synonym do
30
29
 
31
30
  describe "validations" do
32
31
  it "requires a mapping" do
33
- synonym = LucidWorks::Collection::Synonym.new(:mapping => "")
32
+ synonym = LucidWorks::Synonym.new(:mapping => "")
34
33
  synonym.should_not be_valid
35
34
  synonym.errors[:mapping].should == ["can't be blank"]
36
35
  end
37
36
 
38
37
  it "requires the mapping to be a list" do
39
- synonym = LucidWorks::Collection::Synonym.new(:mapping => "car")
38
+ synonym = LucidWorks::Synonym.new(:mapping => "car")
40
39
  synonym.should_not be_valid
41
40
  synonym.errors[:mapping].should == ["must be a comma-separated list"]
42
41
  end
43
42
 
44
43
  it "does not allow '=>' style mappings (for now)" do
45
- synonym = LucidWorks::Collection::Synonym.new(:mapping => "car => auto")
44
+ synonym = LucidWorks::Synonym.new(:mapping => "car => auto")
46
45
  synonym.should_not be_valid
47
46
  synonym.errors[:mapping].should == ["must be a comma-separated list"]
48
47
  end
@@ -50,7 +49,7 @@ describe LucidWorks::Collection::Synonym do
50
49
 
51
50
  describe :save do
52
51
  context "when valid" do
53
- subject { LucidWorks::Collection::Synonym.new(:collection => @collection, :mapping => "car, auto") }
52
+ subject { LucidWorks::Synonym.new(:collection => @collection, :mapping => "car, auto") }
54
53
 
55
54
  it "gets saved in the collection settings" do
56
55
  subject.save
@@ -73,7 +72,7 @@ describe LucidWorks::Collection::Synonym do
73
72
  end
74
73
 
75
74
  context "when invalid" do
76
- subject { LucidWorks::Collection::Synonym.new(:collection => @collection, :mapping => "car") }
75
+ subject { LucidWorks::Synonym.new(:collection => @collection, :mapping => "car") }
77
76
 
78
77
  it "doesn't get saved in the collection settings" do
79
78
  subject.save
@@ -91,7 +90,7 @@ describe LucidWorks::Collection::Synonym do
91
90
  end
92
91
 
93
92
  context "when orphan" do
94
- subject { LucidWorks::Collection::Synonym.new(:mapping => "car, auto") }
93
+ subject { LucidWorks::Synonym.new(:mapping => "car, auto") }
95
94
 
96
95
  it "returns false" do
97
96
  subject.save.should be(false)
@@ -94,13 +94,13 @@ describe LucidWorks::Collection do
94
94
 
95
95
  context "for a collection with some activities" do
96
96
  before do
97
- activity = LucidWorks::Collection::Activity.create(
97
+ activity = LucidWorks::Activity.create(
98
98
  :type => 'optimize',
99
99
  :start_time => 8600,
100
100
  :collection => @collection
101
101
  )
102
102
  activity.should be_persisted
103
- activity = LucidWorks::Collection::Activity.create(
103
+ activity = LucidWorks::Activity.create(
104
104
  :type => 'spelling',
105
105
  :start_time => 8600,
106
106
  :collection => @collection
@@ -112,7 +112,7 @@ describe LucidWorks::Collection do
112
112
  activities = @collection.activities
113
113
  activities.count.should == 2
114
114
  activities.each do |activity|
115
- activity.should be_a(LucidWorks::Collection::Activity)
115
+ activity.should be_a(LucidWorks::Activity)
116
116
  end
117
117
  end
118
118
  end
@@ -122,7 +122,7 @@ describe LucidWorks::Collection do
122
122
  before do
123
123
  @collection = @server.collection('collection1')
124
124
  # require 'ruby-debug'; debugger
125
- # activity = LucidWorks::Collection::Activity.create(
125
+ # activity = LucidWorks::Activity.create(
126
126
  # :type => 'optimize',
127
127
  # :start_time => 8600,
128
128
  # :collection => @collection
@@ -137,7 +137,7 @@ describe LucidWorks::Collection do
137
137
  :template => @template,
138
138
  :parent => @server)
139
139
 
140
- LucidWorks::Collection::Activity.create(activity_params.merge(:parent => c))
140
+ LucidWorks::Activity.create(activity_params.merge(:parent => c))
141
141
  c.activities.size.should == 1
142
142
  c.prime_activities
143
143
  c.activities.size.should == 4
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: lucid_works
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.6.18
5
+ version: 0.6.19
6
6
  platform: ruby
7
7
  authors:
8
8
  - Sam Pierson
@@ -111,19 +111,18 @@ files:
111
111
  - Rakefile
112
112
  - config/locales/en.yml
113
113
  - lib/lucid_works.rb
114
+ - lib/lucid_works/activity.rb
115
+ - lib/lucid_works/activity/history.rb
116
+ - lib/lucid_works/activity/status.rb
114
117
  - lib/lucid_works/associations.rb
115
118
  - lib/lucid_works/associations/has_many.rb
116
119
  - lib/lucid_works/associations/has_one.rb
117
120
  - lib/lucid_works/associations/proxy.rb
118
121
  - lib/lucid_works/base.rb
119
122
  - lib/lucid_works/collection.rb
120
- - lib/lucid_works/collection/activity.rb
121
- - lib/lucid_works/collection/activity/history.rb
122
- - lib/lucid_works/collection/activity/status.rb
123
123
  - lib/lucid_works/collection/index.rb
124
124
  - lib/lucid_works/collection/info.rb
125
125
  - lib/lucid_works/collection/settings.rb
126
- - lib/lucid_works/collection/synonym.rb
127
126
  - lib/lucid_works/crawler.rb
128
127
  - lib/lucid_works/datasource.rb
129
128
  - lib/lucid_works/datasource/crawldata.rb
@@ -145,6 +144,7 @@ files:
145
144
  - lib/lucid_works/schema.rb
146
145
  - lib/lucid_works/server.rb
147
146
  - lib/lucid_works/simple_naming.rb
147
+ - lib/lucid_works/synonym.rb
148
148
  - lib/lucid_works/utils.rb
149
149
  - lib/lucid_works/version.rb
150
150
  - lucid_works.gemspec
@@ -1,191 +0,0 @@
1
- require 'active_support/core_ext/numeric/time.rb'
2
- module LucidWorks
3
- class Collection
4
- class Activity < Base
5
- TYPES = %w{ optimize spelling click autocomplete}
6
-
7
- # Unlike Datasource schedules, the API allows multiples of these
8
- # So, to be honest with gem users, we can't really say this:
9
- # self.singleton = true
10
- belongs_to :collection
11
- has_many :histories, :class_name => :history
12
- has_one :status
13
-
14
- schema do
15
- attribute :period
16
- attribute :start_time, :iso8601
17
- attribute :active, :boolean
18
- attribute :type, :string, :values => TYPES, :omit_during_update => true
19
- end
20
-
21
- validates_presence_of :type, :start_time
22
- validates_numericality_of :period, :allow_blank => true
23
-
24
- def frequency
25
- case period
26
- when 1.weeks.seconds then 'weekly'
27
- when 1.days.seconds then 'daily'
28
- when 1.hours.seconds then 'hourly'
29
- when 0 then nil
30
- else 'custom'
31
- end
32
- end
33
-
34
- #
35
- # accepts hourly, daily, weekly, and sets period to respective # of seconds
36
- #
37
- def frequency=(frequency)
38
- self.period = case frequency
39
- when 'hourly' then 1.hours.seconds
40
- when 'daily' then 1.days.seconds
41
- when 'weekly' then 1.weeks.seconds
42
- else raise "unknown frequency"
43
- end
44
- end
45
-
46
- #
47
- # predict when action will occur next if active at that time
48
- #
49
- def next_start
50
- return start_time if (now = Time.now) <= start_time
51
- # require 'ruby-debug'; debugger
52
- time_since_start = now - start_time
53
- last_interval_num = (time_since_start / period).to_i
54
- next_interval_num = if (time_since_start % period) == 0
55
- # this is sort of a stupid condition b/c time precision is millisecond or less
56
- # for human purposes we wouldn't care if the result were as though the call
57
- # happened a millisecond later. But whatever.
58
- last_interval_num # the next interval *is* the last interval if it is exactly now
59
- else
60
- last_interval_num + 1
61
- end
62
- start_time + period * next_interval_num
63
- end
64
-
65
- #
66
- # phantom attribute for compiling real start time and frequency from appropriate form data
67
- # Allows the user to specify a schedule simply with repeat interval (hourly, daily, weekly)
68
- # and time within the interval to run (e.g 5 past, or Tuesdays at 2:15)
69
- #
70
- # We have to figure out when the actual start time will be because we are not asking
71
- # the user for this. It needs to be:
72
- # * at the requested time relative to the interval chosen
73
- # * as soon as possible
74
- # * in the future
75
- #
76
- # This is obvious to humans, but when computing it, you run into the following problem. It
77
- # happens with all interval sizes, but for the sake of example, we'll use weekly:
78
- #
79
- # Problem 1) If today is Thursday, and the user asks for "weekly on Wednesdays," Wednesday has
80
- # already happened this week. We have to make sure we pick the nearest wednesday that is in
81
- # the future
82
- #
83
- # Problem 2) If today is Tuesday, and the user asks for "weekly on Wednesdays,", the simple solution
84
- # to problem 1 (start next week instead of this week) causes you to skip this Tuesday, even though
85
- # it is valid and is what the user would expect
86
- #
87
- # The algorith to solve both problems at once is this:
88
- # * From Time.now, back up to the beginning of the interval even if it is in the past.
89
- # * Fast forward to the requested siimple start time
90
- # * If you are still in the past, advance by one interval
91
- #
92
- def schedule=(all_attributes)
93
- # convert to format accepted by Time.advance
94
- if all_attributes['start']
95
- all_attributes['start'].to_options!
96
- all_attributes['start'].each{|k,v| all_attributes['start'][k]=v.to_i}
97
- end
98
-
99
- self.active = all_attributes['active'] if all_attributes.keys.include?('active')
100
-
101
- now = Time.now
102
- self.frequency = all_attributes['frequency']
103
- self.start_time =
104
- case all_attributes['frequency']
105
- when 'weekly'
106
- # require 'ruby-debug'; debugger
107
- start = now.beginning_of_week.advance(all_attributes['start'])
108
- start < now ? start.advance(:weeks => 1) : start
109
- when 'daily'
110
- start = now.beginning_of_day.advance(all_attributes['start'])
111
- start < now ? start.advance(:days => 1) : start
112
- when 'hourly'
113
- start = now.change(:min => 0).advance(all_attributes['start'])
114
- start < now ? start.advance(:hours => 1) : start
115
- else
116
- puts "*** frequency: <#{all_attributes[:frequency]}>"
117
- raise "unexpected frequency encountered"
118
- end
119
- end
120
-
121
- #
122
- # convenince method for setting the current value in a view selector
123
- #
124
- def hour
125
- self.start_time.localtime.hour rescue nil
126
- end
127
-
128
- #
129
- # convenince method for setting the current value in a view selector
130
- #
131
- def min
132
- self.start_time.localtime.min rescue nil
133
- end
134
-
135
- #
136
- # convenince method for setting the current value in a view selector
137
- #
138
- def day_of_week
139
- # subract 1 because '%u' returns 1-7, and this is working with zero-indexed ruby arrays
140
- self.start_time.localtime.strftime('%u').to_i - 1 rescue nil
141
- end
142
-
143
- def start_is_more_than_one_period_in_the_future?
144
- # This works fine with start times that are multiple periods in the past
145
- # because that gives a negative difference, and period is always >= 0
146
- (self.start_time - Time.now) > self.period
147
- end
148
-
149
- #
150
- # convenience method for detecting whether schedule can be represented in simple format
151
- # or should be described as custom (meaning it is beyond the capabilities of the convenience methods)
152
- #
153
- def custom?
154
- return false unless self.start_time
155
- return true if self.frequency == 'custom'
156
- return true if self.start_is_more_than_one_period_in_the_future?
157
- return false
158
- end
159
-
160
- #
161
- # convenience method for setting defaults in a UI that make sense for a user
162
- #
163
- def ui_appropriate_defaults!
164
- if self.start_time.blank? || self.period == 0
165
- self.active = true
166
- end
167
- end
168
-
169
- def t_type
170
- I18n.t(type, :scope => 'activemodel.models.lucid_works.collection.activity.type')
171
- end
172
-
173
- def start
174
- self.start_time = 0
175
- self.active = true
176
- save
177
- end
178
-
179
- private
180
-
181
- def exact(interval, period)
182
- if period % (result = 1.send(interval)) == 0
183
- period / result
184
- else
185
- false
186
- end
187
- end
188
-
189
- end
190
- end
191
- end
@@ -1,63 +0,0 @@
1
- module LucidWorks
2
-
3
- class Collection
4
-
5
- class Synonym
6
- include ActiveModel::Validations
7
- include ActiveModel::Conversion
8
- extend ActiveModel::Naming
9
- extend SimpleNaming
10
-
11
- attr_reader :id, :collection, :persisted
12
- attr_accessor :mapping
13
-
14
- validates_presence_of :mapping
15
- validates_each :mapping, :allow_blank => true do |model, attr, value|
16
- model.errors.add(attr, 'must be a comma-separated list') if value =~ /=>/ || value.split(',').size < 2
17
- end
18
-
19
- def initialize(attributes = {})
20
- @id = attributes[:id]
21
- @collection = attributes[:collection]
22
- @mapping = attributes[:mapping]
23
- @persisted = attributes[:persisted] || false
24
- end
25
-
26
- def persisted?
27
- @persisted
28
- end
29
-
30
- def save
31
- return false unless valid?
32
- if persisted?
33
- settings.synonym_list[id] = mapping
34
- else
35
- settings.synonym_list << mapping
36
- @id = settings.synonym_list.length - 1
37
- end
38
- settings.save
39
- @persisted = true
40
- rescue
41
- false
42
- end
43
-
44
- def update_attributes(attrs_and_values)
45
- attrs_and_values.each do |attr,value|
46
- self.send("#{attr}=", value)
47
- end
48
- save
49
- end
50
-
51
- def destroy
52
- settings.synonym_list.delete_at(id)
53
- settings.save
54
- end
55
-
56
- private
57
-
58
- def settings
59
- collection.settings
60
- end
61
- end
62
- end
63
- end