lucid_works 0.6.29 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.rvmrc +1 -1
  2. data/Rakefile +25 -0
  3. data/config/locales/en.yml +171 -83
  4. data/lib/lucid_works/associations/has_many.rb +2 -2
  5. data/lib/lucid_works/associations/has_one.rb +1 -1
  6. data/lib/lucid_works/associations/proxy.rb +3 -3
  7. data/lib/lucid_works/associations.rb +2 -2
  8. data/lib/lucid_works/base.rb +21 -48
  9. data/lib/lucid_works/collection/click.rb +17 -0
  10. data/lib/lucid_works/collection/settings.rb +0 -1
  11. data/lib/lucid_works/collection.rb +22 -3
  12. data/lib/lucid_works/crawler.rb +13 -0
  13. data/lib/lucid_works/datasource/history.rb +5 -9
  14. data/lib/lucid_works/datasource/status.rb +8 -11
  15. data/lib/lucid_works/datasource.rb +67 -32
  16. data/lib/lucid_works/datasource_property.rb +18 -0
  17. data/lib/lucid_works/datasource_type.rb +23 -0
  18. data/lib/lucid_works/exceptions.rb +1 -0
  19. data/lib/lucid_works/field.rb +43 -2
  20. data/lib/lucid_works/fieldtype.rb +28 -0
  21. data/lib/lucid_works/gem_version.rb +1 -1
  22. data/lib/lucid_works/jdbcdriver.rb +30 -0
  23. data/lib/lucid_works/role.rb +59 -0
  24. data/lib/lucid_works/schema/attribute.rb +86 -0
  25. data/lib/lucid_works/schema/boolean_attribute.rb +34 -0
  26. data/lib/lucid_works/schema/custom_attribute.rb +15 -0
  27. data/lib/lucid_works/schema/integer_attribute.rb +32 -0
  28. data/lib/lucid_works/schema/iso8601_attribute.rb +31 -0
  29. data/lib/lucid_works/schema/string_attribute.rb +22 -0
  30. data/lib/lucid_works/schema.rb +66 -97
  31. data/lib/lucid_works/server.rb +14 -0
  32. data/lib/lucid_works.rb +12 -0
  33. data/spec/fixtures/fake_file_ds_to_be_deleted/.gitkeep +0 -0
  34. data/spec/fixtures/fake_file_ds_to_be_updated/.gitkeep +0 -0
  35. data/spec/fixtures/fake_file_ds_to_get_index_of/.gitkeep +0 -0
  36. data/spec/fixtures/fake_file_ds_to_get_schedule_of/.gitkeep +0 -0
  37. data/spec/fixtures/fake_file_ds_to_get_status_of/.gitkeep +0 -0
  38. data/spec/fixtures/fake_file_ds_to_mess_with_job_of/.gitkeep +0 -0
  39. data/spec/fixtures/fake_file_ds_to_test_progress/.gitkeep +0 -0
  40. data/spec/lib/lucid_works/associations/has_many_spec.rb +4 -3
  41. data/spec/lib/lucid_works/associations/has_one_spec.rb +4 -3
  42. data/spec/lib/lucid_works/base_spec.rb +110 -62
  43. data/spec/lib/lucid_works/collection/activity/history_spec.rb +1 -1
  44. data/spec/lib/lucid_works/collection_spec.rb +17 -17
  45. data/spec/lib/lucid_works/datasource/history_spec.rb +4 -4
  46. data/spec/lib/lucid_works/datasource/status_spec.rb +7 -7
  47. data/spec/lib/lucid_works/datasource_spec.rb +9 -8
  48. data/spec/lib/lucid_works/field_spec.rb +101 -2
  49. data/spec/lib/lucid_works/fieldtype_spec.rb +156 -0
  50. data/spec/lib/lucid_works/schema/attribute_spec.rb +136 -0
  51. data/spec/lib/lucid_works/schema_spec.rb +53 -27
  52. data/spec/spec_helper.rb +3 -50
  53. data/spec/support/active_model_lint.rb +21 -0
  54. data/spec/support/lucid_works.rb +52 -0
  55. metadata +36 -2
@@ -1,3 +1,3 @@
1
1
  module LucidWorks
2
- VERSION = "0.6.29"
2
+ VERSION = "0.7.1"
3
3
  end
@@ -0,0 +1,30 @@
1
+ module LucidWorks
2
+
3
+ # This model is a strange beast.
4
+ # You can DELETE it, but that's about it.
5
+ # GET on the plural resource name returns a list of strings, not hashes
6
+ # so we create these things by hand in Collection
7
+ class Jdbcdriver < Base
8
+ belongs_to :collection
9
+
10
+ schema do
11
+ primary_key :name
12
+ attribute :name
13
+ attribute :file
14
+ end
15
+
16
+ validates_presence_of :name
17
+
18
+ # Dont' let LucidWorks::Base do this as it will try to encode us as JSON
19
+ # In this case we need to let RestClient do it's thing and figure out we should do a multipart post
20
+ def save
21
+ return false unless valid?
22
+ RestClient.post(collection_url, :file => file)
23
+ @persisted = true
24
+ rescue RestClient::Exception => e
25
+ @persisted = false
26
+ attach_errors_to_model(e.response)
27
+ return false
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,59 @@
1
+ module LucidWorks
2
+ class Role < Base
3
+ belongs_to :collection
4
+
5
+ schema do
6
+ attribute :name, :string, :primary_key => true, :omit_during_update => true
7
+ attribute :users, :custom
8
+ attribute :groups#, :custom
9
+ attribute :filters#, :custom
10
+ end
11
+
12
+ def users
13
+ @attributes[:users]
14
+ end
15
+
16
+ def groups
17
+ @attributes[:groups]
18
+ end
19
+
20
+ def filters
21
+ # require 'ruby-debug'; debugger
22
+ @attributes[:filters]
23
+ end
24
+
25
+ def filters_for_text_area
26
+ @attributes[:filters].join("\n")
27
+ end
28
+
29
+ #
30
+ # Accept a comma or space separated list of users, convert to array
31
+ #
32
+ def users=(val)
33
+ @attributes[:users] = string_or_array(val, /[\s,]+/) rescue "Can't interpret #{val.class} as list of users"
34
+ end
35
+
36
+ def groups=(val)
37
+ @attributes[:groups] = string_or_array(val, /[\s,]+/) rescue "Can't interpret #{val.class} as list of groups"
38
+ end
39
+
40
+ def filters=(val)
41
+ @attributes[:filters] = string_or_array(val, /\r+/) rescue "Can't interpret #{val.class} as list of groups"
42
+ # require 'ruby-debug'; debugger
43
+ # @attributes[:filters]
44
+ end
45
+
46
+ private
47
+
48
+ def string_or_array(val, pattern)
49
+ if val.is_a?(String)
50
+ val.split(pattern)
51
+ elsif val.is_a?(Array)
52
+ val
53
+ else
54
+ raise "Don't know how to convert #{val.class} to Array"
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,86 @@
1
+ module LucidWorks
2
+ class Schema
3
+
4
+ class Attribute
5
+ ATTRIBUTES_TYPES = [ :string, :integer, :boolean, :iso8601, :custom ]
6
+ RESERVED_ATTRIBUTE_NAMES = %{ class nil? send caller object_id }
7
+
8
+ attr_reader :schema, :name, :values, :origin
9
+
10
+ class << self
11
+
12
+ def factory(schema, name, type, options={})
13
+ raise "Unknown attribute type: #{type.inspect}" unless ATTRIBUTES_TYPES.include?(type)
14
+ attribute_class = ( "LucidWorks::Schema::" + ("#{type}_attribute".classify) ).constantize
15
+ attribute_class.new(schema, name, options)
16
+ end
17
+
18
+ # Change any characters illegal for an identifier to _
19
+ def sanitize_name(identifier) # :nodoc:
20
+ sane_identifier = identifier.to_s.gsub(/[^\w]/, '_')
21
+ sane_identifier = "_#{sane_identifier}" if RESERVED_ATTRIBUTE_NAMES.include?(sane_identifier)
22
+ sane_identifier.to_sym
23
+ end
24
+ end
25
+
26
+ def initialize(schema, name, options={})
27
+ @schema = schema
28
+ @true_name = name.to_s # External representation. Will be used when sending data back to REST API
29
+ @name = self.class.sanitize_name(name) # Internal representation. A symbol.
30
+ @origin = options[:origin]
31
+ @omit_during_update = options[:omit_during_update]
32
+ @omit_when_blank = options[:omit_when_blank]
33
+ @nil_when_blank = options[:nil_when_blank]
34
+ @values = options[:values]
35
+ end
36
+
37
+ def type
38
+ raise "type() method must be implemented by Attribute subclass"
39
+ end
40
+
41
+ def omit_during_update? ; @omit_during_update end
42
+ def omit_when_blank? ; @omit_when_blank end
43
+ def nil_when_blank? ; @nil_when_blank end
44
+
45
+ def create_accessors_for_attribute(klass) # :nodoc:
46
+ klass.class_eval <<-EOF, __FILE__, __LINE__+1
47
+ def #{name} # def foo
48
+ @attributes[:#{name}] # @attributes[:foo]
49
+ end # end
50
+ EOF
51
+ end
52
+
53
+ def encode_and_insert(value, hash, is_update) # :nodoc:
54
+ return if omit_during_update? && is_update
55
+ return if omit_when_blank? && (value.nil? || value == "")
56
+ hash[@true_name.to_s] = encode(value)
57
+ end
58
+
59
+ def human_value(value)
60
+ if values
61
+ # If this attribute was defined with a set of :values,
62
+ # assume we can get translations for those valuesfrom the L10n database.
63
+ l10n_scope = %w{activemodel models} + schema.model.name.underscore.split('/') + [name]
64
+ return I18n.t(value, :scope => l10n_scope, :default => value)
65
+ end
66
+ value.to_s
67
+
68
+ rescue
69
+ value.to_s
70
+ end
71
+
72
+ def to_select
73
+ raise "Can't to_select for attribute #{name} as it has no values" unless values
74
+ values.map do |value|
75
+ [human_value(value), value]
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def encode(value)
82
+ value
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,34 @@
1
+ module LucidWorks
2
+ class Schema
3
+
4
+ class BooleanAttribute < Attribute
5
+
6
+ def type
7
+ :boolean
8
+ end
9
+
10
+ def create_accessors_for_attribute(klass) # :nodoc:
11
+ super
12
+
13
+ klass.class_eval <<-EOF, __FILE__, __LINE__+1
14
+ def #{name}? # def foo?
15
+ @attributes[:#{name}] # @attributes[:foo]
16
+ end # end
17
+
18
+ def #{name}=(new_value) # def foo=(new_value)
19
+ begin # begin
20
+ @attributes[:#{name}] = to_bool(new_value) # @attributes[:foo] = to_bool(new_value)
21
+ rescue # rescue
22
+ raise "Expected #{name} to take a boolean"+ # raise "Expected <some_bool> to take a boolean
23
+ " value, but '\#\{new_value}' is ambiguous" # " value, but 'frozbot' is ambiguous"
24
+ end # end
25
+ end # end
26
+ EOF
27
+ end
28
+
29
+ def human_value(value)
30
+ value.to_yesno
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,15 @@
1
+ module LucidWorks
2
+ class Schema
3
+
4
+ class CustomAttribute < Attribute
5
+
6
+ def type
7
+ :custom
8
+ end
9
+
10
+ def create_accessors_for_attribute(klass) # :nodoc:
11
+ # Do nothing. Developer will provide own accessors.
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ module LucidWorks
2
+ class Schema
3
+
4
+ class IntegerAttribute < Attribute
5
+ include ActionView::Helpers::NumberHelper rescue nil
6
+
7
+ def type
8
+ :integer
9
+ end
10
+
11
+ def create_accessors_for_attribute(klass) # :nodoc:
12
+ super
13
+
14
+ klass.class_eval <<-EOF, __FILE__, __LINE__+1
15
+ def #{name}=(new_value)
16
+ if new_value.blank? && (self.class.schema[:#{name}].nil_when_blank? ||
17
+ self.class.schema[:#{name}].omit_when_blank?)
18
+ new_value = nil
19
+ else
20
+ new_value = new_value.to_i
21
+ end
22
+ @attributes[:#{name}] = new_value
23
+ end
24
+ EOF
25
+ end
26
+
27
+ def human_value(value)
28
+ number_with_delimiter(value)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ module LucidWorks
2
+ class Schema
3
+
4
+ class Iso8601Attribute < Attribute
5
+
6
+ def type
7
+ :iso8601
8
+ end
9
+
10
+ def create_accessors_for_attribute(klass) # :nodoc:
11
+ super
12
+
13
+ klass.class_eval <<-EOF, __FILE__, __LINE__+1
14
+ def #{name}=(new_value)
15
+ if new_value.kind_of?(String)
16
+ @attributes[:#{name}] = Time.iso8601(new_value)
17
+ else
18
+ @attributes[:#{name}] = new_value
19
+ end
20
+ end
21
+ EOF
22
+ end
23
+
24
+ private
25
+
26
+ def encode(value)
27
+ value.iso8601 rescue value
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,22 @@
1
+ module LucidWorks
2
+ class Schema
3
+
4
+ class StringAttribute < Attribute
5
+
6
+ def type
7
+ :string
8
+ end
9
+
10
+ def create_accessors_for_attribute(klass) # :nodoc:
11
+ super
12
+
13
+ klass.class_eval <<-EOF, __FILE__, __LINE__+1
14
+ def #{name}=(new_value)
15
+ new_value = nil if new_value.blank? && self.class.schema[:#{name}].nil_when_blank?
16
+ @attributes[:#{name}] = new_value
17
+ end
18
+ EOF
19
+ end
20
+ end
21
+ end
22
+ end
@@ -3,7 +3,8 @@ module LucidWorks
3
3
  # Schema is used to delare attributes for a model.
4
4
 
5
5
  class Schema < ActiveSupport::HashWithIndifferentAccess
6
- ATTRIBUTES_TYPES = [ :string, :integer, :boolean, :iso8601, :custom ]
6
+
7
+ attr_reader :model
7
8
 
8
9
  # Initializes the schema, taking a block of schema declarations.
9
10
  # Typically it is called from LucidWorks::Base, e.g.:
@@ -22,11 +23,17 @@ module LucidWorks
22
23
  # end
23
24
  # end
24
25
  #
25
- def initialize
26
+ def initialize(model)
27
+ @model = model
26
28
  @primary_key = :id
27
29
  @dynamic_attributes = true
28
30
  end
29
31
 
32
+ # If this model's primary key is something other than 'id',
33
+ # use the primary_key method it indicate that. e.g.
34
+ #
35
+ # primary_key "name"
36
+
30
37
  def primary_key(key=nil)
31
38
  @primary_key = key.to_sym if key
32
39
  @primary_key
@@ -41,9 +48,62 @@ module LucidWorks
41
48
  @dynamic_attributes = !!on unless on.nil?
42
49
  @dynamic_attributes
43
50
  end
44
-
51
+
45
52
  alias :dynamic_attributes? :dynamic_attributes
46
53
 
54
+ def has_attribute?(name)
55
+ has_key? Attribute.sanitize_name(name)
56
+ end
57
+
58
+ def find_or_create_attribute(name)
59
+ attrname = Attribute.sanitize_name(name)
60
+ attribute = fetch(attrname, nil)
61
+ unless attribute
62
+ if dynamic_attributes?
63
+ attribute = add_attribute(name, :string)
64
+ else
65
+ raise "unknown attribute: \"#{attr}\""
66
+ end
67
+ end
68
+ attribute
69
+ end
70
+
71
+ # Used for classes that have no predefined schema.
72
+ # When the class is retrieved.
73
+ def add_attribute(name, type=:string) # :nodoc:
74
+ raise "Class #{model.name} already has attribute #{name}" if has_attribute?(Attribute.sanitize_name(name))
75
+ attribute = Attribute.factory(self, name, type, :origin => :added_later)
76
+ attribute.create_accessors_for_attribute(model)
77
+ self[attribute.name] = attribute
78
+ end
79
+
80
+ # Create accessors for all attributes defined in the schema.
81
+ def create_accessors_for_attributes(klass) # :nodoc:
82
+ self.values.each do |attr|
83
+ attr.create_accessors_for_attribute(klass)
84
+ end
85
+ end
86
+
87
+ # Reset the schema to the originally defined version (before we added a bunch of attributes during load or create)
88
+ def reset!
89
+ each do |name, attr|
90
+ if attr.origin != :original
91
+ model.class_eval <<-EOF, __FILE__, __LINE__+1
92
+ undef_method(:#{name})
93
+ undef_method(:"#{name}=")
94
+ EOF
95
+ delete(name)
96
+ end
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ ###################################################################################################################
103
+ # The following are private methods, that will be accessed when LucidWorks::Base does an
104
+ # instance_eval in response to a schema(&block) call.
105
+ ###################################################################################################################
106
+
47
107
  # Declare a single attribute.
48
108
  #
49
109
  # Attributes may be of the following types:
@@ -66,9 +126,10 @@ module LucidWorks
66
126
  # [:omit_when_blank => true] When this attribute is blank?, don't send it to the server during save.
67
127
 
68
128
  def attribute(name, type=:string, options={})
69
- raise "Unknown attribute type: #{type.inspect}" unless ATTRIBUTES_TYPES.include?(type)
70
129
  primary_key name if options.delete(:primary_key)
71
- self[name] = options.merge(:type => type)
130
+ options[:origin] = :original
131
+ attr = Attribute.factory(self, name, type, options)
132
+ self[attr.name] = attr
72
133
  end
73
134
 
74
135
  # Specify multiple attributes. Options apply to all attributes, e.g.
@@ -85,97 +146,5 @@ module LucidWorks
85
146
  attribute name, type, options
86
147
  end
87
148
  end
88
-
89
- def has_attribute?(name)
90
- has_key? sanitize_identifier(name)
91
- end
92
-
93
- def attrs_to_omit_during_update
94
- select { |k,v| v['omit_during_update'] == true }.keys
95
- end
96
-
97
- # Used for classes that have no predefined schema.
98
- # When the class is retrieved.
99
- def add_attribute(klass, name, type=:string) # :nodoc:
100
- attr = sanitize_identifier(name)
101
- raise "Class #{klass.name} already has attribute #{attr}" if has_attribute?(attr)
102
- self[attr] = { :type => type }
103
- create_attribute(klass, attr)
104
- end
105
-
106
- # Create accessors for all attributes defined in the schema.
107
- def create_accessors_for_attributes(klass) # :nodoc:
108
- self.keys.each do |attr|
109
- create_attribute(klass, attr)
110
- end
111
- end
112
-
113
- def create_attribute(klass, attribute) # :nodoc:
114
- klass.class_eval <<-EOF, __FILE__, __LINE__+1
115
- def #{attribute} # def foo
116
- @attributes[:#{attribute}] # @attributes[:foo]
117
- end # end
118
- EOF
119
-
120
- case self[attribute][:type]
121
- when :boolean
122
- klass.class_eval <<-EOF, __FILE__, __LINE__+1
123
- def #{attribute}? # def foo?
124
- @attributes[:#{attribute}] # @attributes[:foo]
125
- end # end
126
-
127
- def #{attribute}=(new_value) # def foo=(new_value)
128
- begin # begin
129
- @attributes[:#{attribute}] = to_bool(new_value) # @attributes[:foo] = to_bool(new_value)
130
- rescue # rescue
131
- raise "Expected #{attribute} to take a boolean"+ # raise "Expected <some_bool> to take a boolean
132
- " value, but '\#\{new_value}' is ambiguous" # " value, but 'frozbot' is ambiguous"
133
- end # end
134
- end # end
135
- EOF
136
- when :string
137
- klass.class_eval <<-EOF, __FILE__, __LINE__+1
138
- def #{attribute}=(new_value) # def foo=(new_value)
139
- new_value = nil if new_value.blank? && self.class.schema[:#{attribute}][:nil_when_blank]
140
- @attributes[:#{attribute}] = new_value # @attributes[:foo] = new_value
141
- end # end
142
- EOF
143
- when :integer
144
- klass.class_eval <<-EOF, __FILE__, __LINE__+1
145
- def #{attribute}=(new_value)
146
- if new_value.blank? && (self.class.schema[:#{attribute}][:nil_when_blank] ||
147
- self.class.schema[:#{attribute}][:omit_when_blank])
148
- new_value = nil
149
- else
150
- new_value = new_value.to_i
151
- end
152
- @attributes[:#{attribute}] = new_value
153
- end
154
- EOF
155
- when :iso8601
156
- klass.class_eval <<-EOF, __FILE__, __LINE__+1
157
- def #{attribute}=(new_value)
158
- if new_value.kind_of?(String)
159
- @attributes[:#{attribute}] = Time.iso8601(new_value)
160
- else
161
- @attributes[:#{attribute}] = new_value
162
- end
163
- end
164
- EOF
165
- when :custom
166
- # Do nothing. Developer will provide own accessors.
167
- else
168
- klass.class_eval <<-EOF, __FILE__, __LINE__+1
169
- def #{attribute}=(new_value) # def foo=(new_value)
170
- @attributes[:#{attribute}] = new_value # @attributes[:foo] = new_value
171
- end # end
172
- EOF
173
- end
174
- end
175
-
176
- # Change any characters illegal for an identifier to _
177
- def sanitize_identifier(identifier) # :nodoc:
178
- identifier.to_s.gsub(/[^\w]/, '_').to_sym
179
- end
180
149
  end
181
150
  end