sethyates-content_manager 0.4.0 → 1.0.0

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.
Files changed (40) hide show
  1. data/README.rdoc +253 -1
  2. data/VERSION +1 -1
  3. data/content_manager.gemspec +38 -2
  4. data/doc/created.rid +1 -0
  5. data/doc/files/README_rdoc.html +487 -0
  6. data/doc/fr_class_index.html +26 -0
  7. data/doc/fr_file_index.html +27 -0
  8. data/doc/fr_method_index.html +26 -0
  9. data/doc/index.html +24 -0
  10. data/doc/rdoc-style.css +208 -0
  11. data/generators/component_scaffold/USAGE +28 -0
  12. data/generators/component_scaffold/component_scaffold_generator.rb +84 -0
  13. data/generators/component_scaffold/templates/controller.rb +85 -0
  14. data/generators/component_scaffold/templates/model.rb +5 -0
  15. data/generators/component_scaffold/templates/style.css +1 -0
  16. data/generators/component_scaffold/templates/view_edit.html.erb +13 -0
  17. data/generators/component_scaffold/templates/view_index.html.erb +22 -0
  18. data/generators/component_scaffold/templates/view_new.html.erb +12 -0
  19. data/generators/component_scaffold/templates/view_show.html.erb +3 -0
  20. data/generators/content_scaffold/USAGE +28 -0
  21. data/generators/content_scaffold/content_scaffold_generator.rb +83 -0
  22. data/generators/content_scaffold/templates/controller.rb +85 -0
  23. data/generators/content_scaffold/templates/model.rb +8 -0
  24. data/generators/content_scaffold/templates/view_edit.html.erb +13 -0
  25. data/generators/content_scaffold/templates/view_index.html.erb +22 -0
  26. data/generators/content_scaffold/templates/view_new.html.erb +12 -0
  27. data/generators/content_scaffold/templates/view_show.html.erb +8 -0
  28. data/lib/component.rb +28 -0
  29. data/lib/content/adapters/base.rb +79 -0
  30. data/lib/content/adapters/cabinet_adapter.rb +62 -0
  31. data/lib/content/adapters/tyrant_adapter.rb +73 -0
  32. data/lib/content/item.rb +178 -0
  33. data/lib/content/item_association_class_methods.rb +148 -0
  34. data/lib/content/item_class_methods.rb +71 -0
  35. data/lib/content/item_dirty_methods.rb +171 -0
  36. data/lib/content/item_finder_class_methods.rb +203 -0
  37. data/lib/content/manager.rb +105 -0
  38. data/lib/content/sublayout.rb +44 -0
  39. data/lib/content/template.rb +24 -0
  40. metadata +38 -2
@@ -0,0 +1,62 @@
1
+ require 'rufus/tokyo'
2
+
3
+ module Content
4
+ module Adapters
5
+ class CabinetAdapter < Base
6
+ def initialize(options = {})
7
+ file = options[:database] || options["database"] || "db/content.tct"
8
+ mode = options[:mode] || options["mode"] || "create"
9
+ @connection = Rufus::Tokyo::Table.new(file, mode)
10
+ end
11
+
12
+ def prepare_query(klass, query_options)
13
+ end
14
+
15
+ def run_query(klass, query_options)
16
+ results = nil
17
+ ms = Benchmark.ms do
18
+ query_options[:limit] ||= 1000
19
+ results = @connection.query { |q|
20
+ (query_options[:conditions] || {}).each { |cond| q.add_condition cond[0], :eq, cond[1] }
21
+ (query_options[:order] || []).each {|order| q.order_by order }
22
+ }.collect {|r| r.symbolize_keys }
23
+ end
24
+ log_select(query_options, klass, ms)
25
+ results
26
+ end
27
+
28
+ def count(klass, query_options)
29
+ run_query(klass, query_options).length
30
+ end
31
+
32
+ def get_record_by_id(klass, id)
33
+ record = nil
34
+ ms = Benchmark.ms do
35
+ record = @connection[id.to_s].symbolize_keys
36
+ end
37
+ log_select({:conditions => {:__id => id, :content_type => klass.name.to_s}}, klass, ms)
38
+ record
39
+ end
40
+
41
+ def save_record(klass, id, attributes)
42
+ ms = Benchmark.ms do
43
+ @connection[id.to_s] = attributes.stringify_keys
44
+ end
45
+ log_update(id, attributes, klass, ms)
46
+ true
47
+ end
48
+
49
+ def delete_record_by_id(klass, id)
50
+ ms = Benchmark.ms do
51
+ @connection.delete id
52
+ end
53
+ log_delete(id, klass, ms)
54
+ true
55
+ end
56
+
57
+ def genuid
58
+ @connection.genuid
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,73 @@
1
+ require 'tokyo_tyrant'
2
+
3
+ module Content
4
+ module Adapters
5
+ class TyrantAdapter < Base
6
+ def initialize(options = {})
7
+ host = options[:host] || options["host"] || "localhost"
8
+ port = options[:port] || options["port"] || 1978
9
+ @connection = TokyoTyrant::Table.new(host, port)
10
+ @logger = ActiveRecord::Base.logger
11
+ end
12
+
13
+ def prepare_query(klass, query_options)
14
+ query_options[:limit] ||= 1000
15
+ query_options[:offset] || -1
16
+ returning @connection.query do |q|
17
+ (query_options[:conditions] || {}).each { |key, value| q.condition(key, :streq, value) }
18
+ (query_options[:order] || []).each { |order| q.order_by(order, :strasc) }
19
+ q.limit(query_options[:limit], query_options[:offset])
20
+ end
21
+ end
22
+
23
+ def run_query(klass, query_options)
24
+ results = nil
25
+ ms = Benchmark.ms do
26
+ query = prepare_query klass, query_options
27
+ results = query.get
28
+ end
29
+ log_select(query_options, klass, ms)
30
+ results
31
+ end
32
+
33
+ def count(klass, query_options)
34
+ results = nil
35
+ ms = Benchmark.ms do
36
+ query = prepare_query klass, query_options
37
+ results = query.searchcount
38
+ end
39
+ log_count(query_options, klass, ms)
40
+ results
41
+ end
42
+
43
+ def get_record_by_id(klass, id)
44
+ record = nil
45
+ ms = Benchmark.ms do
46
+ record = @connection[id]
47
+ end
48
+ log_select({:conditions => {:__id => id, :content_type => klass.name.to_s}}, klass, ms)
49
+ record
50
+ end
51
+
52
+ def save_record(klass, id, attributes)
53
+ ms = Benchmark.ms do
54
+ @connection[id] = attributes
55
+ end
56
+ log_update(id, attributes, klass, ms)
57
+ true
58
+ end
59
+
60
+ def delete_record_by_id(klass, id)
61
+ ms = Benchmark.ms do
62
+ @connection.delete id
63
+ end
64
+ log_delete(id, klass, ms)
65
+ true
66
+ end
67
+
68
+ def genuid
69
+ @connection.genuid
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,178 @@
1
+ module Content
2
+ class Item
3
+ extend ItemAssociationClassMethods
4
+ extend ItemFinderClassMethods
5
+ extend ItemClassMethods
6
+
7
+ fields :status, :version, :url, :heading, :summary, :content_type
8
+ belongs_to :template
9
+
10
+ def initialize(attrs = {})
11
+ @attributes = { :content_type => self.class.name.to_s }
12
+ @attributes.merge!(attrs.symbolize_keys) unless attrs.nil?
13
+ @new_record = !@attributes.has_key?(:__id)
14
+ yield(self) if block_given?
15
+ end
16
+
17
+ def save
18
+ create_or_update
19
+ end
20
+
21
+ def create_or_update
22
+ raise ActiveRecord::ReadOnlyRecord if readonly?
23
+ result = new_record? ? create : update
24
+ result != false
25
+ end
26
+
27
+ def create
28
+ self[:__id] = self.class.connection.genuid if self[:__id].nil?
29
+ if new_record? or changed?
30
+ saved_attributes = {}
31
+ self.class.ignored_attributes.each {|k| self["#{k.to_s.singularize}_ids"] = self[k].collect(&:id) if instance_variable_get("@#{k}_loaded".to_sym) }
32
+ @attributes.each {|k,v| saved_attributes[k] = v.is_a?(String) ? v : v.to_json unless self.class.ignored_attributes.include? k }
33
+ self.class.connection.save_record(self.class, self.id, saved_attributes)
34
+ @new_record = false
35
+ changed_attributes.clear
36
+ end
37
+ self
38
+ end
39
+ alias update create
40
+ alias respond_to_without_attributes? respond_to?
41
+
42
+ def save!
43
+ save
44
+ nil
45
+ end
46
+
47
+ def destroy
48
+ self.class.connection.delete_record_by_id self.class, id
49
+ end
50
+
51
+ def readonly?
52
+ false
53
+ end
54
+
55
+ def new_record?
56
+ @new_record
57
+ end
58
+
59
+ def changed?
60
+ !changed_attributes.empty?
61
+ end
62
+
63
+ def [](key)
64
+ read_attribute key
65
+ end
66
+
67
+ def []=(key, value)
68
+ write_attribute key, value
69
+ end
70
+
71
+ def read_attribute(attr_name)
72
+ @attributes[attr_name.to_sym]
73
+ end
74
+
75
+ def write_attribute(attr_name, value)
76
+ sym = attr_name.to_sym
77
+ if !new_record? and (@attributes[sym].nil? or @attributes[sym] != value)
78
+ attribute_will_change!(sym)
79
+ end
80
+ if value.nil?
81
+ @attributes.delete sym
82
+ else
83
+ @attributes[sym] = value
84
+ end
85
+ end
86
+
87
+ def query_attribute(attr_name)
88
+ value = read_attribute(attr_name.to_sym)
89
+ if Numeric === value || value !~ /[^0-9]/
90
+ !value.to_i.zero?
91
+ else
92
+ return false if ActiveRecord::ConnectionAdapters::Column::FALSE_VALUES.include?(value)
93
+ !value.blank?
94
+ end
95
+ end
96
+
97
+ def update_attributes(attrs)
98
+ unless attrs.nil?
99
+ attrs.each do |key, value|
100
+ self[key.to_sym] = value
101
+ end
102
+ end
103
+ save
104
+ end
105
+
106
+ def method_missing(name, *arguments)
107
+ if arguments.length == 0
108
+ self[name] if @attributes.has_key? name
109
+ elsif arguments.length == 1 and name.to_s.match(/^(.+)=$/)
110
+ self[$1.to_sym] = arguments.first
111
+ else
112
+ super
113
+ end
114
+ end
115
+
116
+ def to_param
117
+ id.to_s
118
+ end
119
+
120
+ def to_yaml
121
+ @attributes.to_yaml
122
+ end
123
+
124
+ def to_json
125
+ @attributes.to_json
126
+ end
127
+
128
+ def to_xml(options = {})
129
+ xml = Builder::XmlMarkup.new(:indent => options[:indent])
130
+ xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
131
+ xml.tag!(self.class.name.underscore.gsub('/', '-').dasherize) do |inner_xml|
132
+ self.class.serialized_attributes.each {|attr_name| inner_xml.tag! attr_name, @attributes[attr_name] unless @attributes[attr_name].nil? }
133
+ yield(inner_xml) if block_given?
134
+ end
135
+ xml.target!
136
+ end
137
+
138
+ def id
139
+ self[:__id].to_i unless self[:__id].nil?
140
+ end
141
+
142
+ private
143
+ def changed_attributes
144
+ @changed_attributes ||= {}
145
+ end
146
+ end
147
+ end
148
+
149
+ Content::Item.class_eval do
150
+ include Content::ItemDirtyMethods
151
+ include ActiveRecord::Validations
152
+ include ActiveRecord::Callbacks
153
+ end
154
+
155
+
156
+ # RDBQC*
157
+ # STREQ - for string which is equal to the expression
158
+ # STRINC - for string which is included in the expression
159
+ # STRBW - for string which begins with the expression
160
+ # STREW - for string which ends with the expression
161
+ # STRAND - for string which includes all tokens in the expression
162
+ # STROR - for string which includes at least one token in the expression
163
+ # STROREQ - for string which is equal to at least one token in the expression
164
+ # STRRX - for string which matches regular expressions of the expression
165
+ # NUMEQ - for number which is equal to the expression
166
+ # NUMGT - for number which is greater than the expression
167
+ # NUMGE - for number which is greater than or equal to the expression
168
+ # NUMLT - for number which is less than the expression
169
+ # NUMLE - for number which is less than or equal to the expression
170
+ # NUMBT - for number which is between two tokens of the expression
171
+ # NUMOREQ - for number which is equal to at least one token in the expression
172
+ # FTSPH - for full-text search with the phrase of the expression
173
+ # FTSAND - for full-text search with all tokens in the expression
174
+ # FTSOR - for full-text search with at least one token in the expression
175
+ # FTSEX - for full-text search with the compound expression.
176
+ # All operations can be flagged by bitwise-or:
177
+ # NEGATE - for negation
178
+ # NOIDX - for using no index.
@@ -0,0 +1,148 @@
1
+ module Content
2
+ module ItemAssociationClassMethods
3
+ def ignored_attributes
4
+ @ignored_attributes ||= []
5
+ end
6
+
7
+ def serialized_attributes
8
+ @serialized_attributes ||= []
9
+ end
10
+
11
+ def has_many(name, options = {})
12
+ raise "name must be plural" unless name.to_s == name.to_s.pluralize
13
+ name_ids = "#{name.to_s.singularize}_ids".to_sym
14
+ ignored_attributes << name
15
+ serialized_attributes << name_ids
16
+
17
+ define_method(name_ids) do
18
+ if instance_variable_get("@#{name}_loaded".to_sym)
19
+ self[name_ids] = self[name].collect(&:id)
20
+ self[name] = nil
21
+ instance_variable_set("@#{name}_loaded".to_sym, false)
22
+ else
23
+ if self[name_ids].nil?
24
+ self[name_ids] = []
25
+ else
26
+ self[name_ids] = ActiveSupport::JSON.decode(self[name_ids]) if !self[name_ids].is_a?(Array) and self[name_ids].is_a? String
27
+ end
28
+ end
29
+ self[name_ids]
30
+ end
31
+
32
+ define_method("#{name_ids}=".to_sym) do |val|
33
+ self[name] = nil
34
+ instance_variable_set("@#{name}_loaded".to_sym, false)
35
+
36
+ if val.is_a? Content::Item
37
+ self[name_ids] = [val.id.to_i]
38
+ elsif !val.is_a? Array
39
+ self[name_ids] = [val.to_i]
40
+ else
41
+ self[name_ids] = val
42
+ end
43
+ end
44
+
45
+ define_method(name) do
46
+ ary = self[name]
47
+ if ary.nil?
48
+ self[name] = ary = (self.send(name_ids) || []).collect {|id| self.class.find(id.to_i) }
49
+ instance_variable_set("@#{name}_loaded".to_sym, true)
50
+ self[name_ids] = nil
51
+ end
52
+ ary
53
+ end
54
+
55
+ define_method("#{name}=".to_sym) do |val|
56
+ if val.is_a? Array
57
+ instance_variable_set("@#{name}_loaded".to_sym, true)
58
+ self[name] = val
59
+ self[name_ids] = nil
60
+ elsif val.nil?
61
+ instance_variable_set("@#{name}_loaded".to_sym, false)
62
+ self[name] = nil
63
+ self[name_ids] = nil
64
+ end
65
+ end
66
+
67
+ define_method("#{name}_loaded".to_sym) do
68
+ instance_variable_get("@#{name}_loaded".to_sym)
69
+ end
70
+ end
71
+
72
+ def belongs_to(name, options = {})
73
+ raise "name must be singular" unless name.to_s == name.to_s.singularize
74
+ name_id = "#{name}_id".to_sym
75
+ ignored_attributes << name
76
+ serialized_attributes << name_id
77
+
78
+ define_method(name_id) do
79
+ self[name_id].to_i
80
+ end
81
+
82
+ define_method("#{name_id}=".to_sym) do |val|
83
+ if val.is_a? Content::Item
84
+ self[name] = val
85
+ self[name_id] = val.id.to_i
86
+ else
87
+ self[name_id] = val.to_i
88
+ end
89
+ end
90
+
91
+ define_method(name) do
92
+ self[name] ||= self.class.find(self[name_id].to_i)
93
+ end
94
+
95
+ define_method("#{name}=".to_sym) do |val|
96
+ if val.is_a? Content::Item
97
+ val.save! if val.new_record?
98
+ self[name] = val
99
+ self[name_id] = val.id.to_i
100
+ end
101
+ end
102
+ end
103
+
104
+ alias :has_one :belongs_to
105
+
106
+ def field(name_or_ary, field_type = :string)
107
+ names = name_or_ary
108
+ names = [name_or_ary] unless name_or_ary.is_a? Array
109
+ names.each do |name|
110
+ serialized_attributes << name
111
+ field_klass = field_type.to_s.camelcase.constantize
112
+
113
+ define_method(name) do
114
+ self[name] = ActiveSupport::JSON.decode(self[name]) if !self[name].is_a?(field_klass) and self[name].is_a? String
115
+ self[name]
116
+ end
117
+
118
+ define_method("#{name}=".to_sym) do |val|
119
+ self[name] = val
120
+ end
121
+
122
+ define_method("#{name}_changed?".to_sym) do
123
+ self.changed_attributes.has_key? name
124
+ end
125
+
126
+ define_method("#{name}_change".to_sym) do
127
+ [self.changed_attributes[name], self[name]] if self.changed_attributes.has_key? name
128
+ end
129
+
130
+ define_method("#{name}_was".to_sym) do
131
+ if self.changed_attributes.has_key? name
132
+ self.changed_attributes[name]
133
+ else
134
+ self[name]
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ def fields(*names)
141
+ field names
142
+ end
143
+
144
+ def index(name, index_type = :lexical)
145
+ self.connection.set_index name, index_type
146
+ end
147
+ end
148
+ end