sethyates-content_manager 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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