lucid_works 0.6.18 → 0.6.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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