hobofields 0.7.5 → 0.8
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.
- data/Manifest +12 -3
- data/hobofields.gemspec +23 -9
- data/lib/hobo_fields/email_address.rb +6 -6
- data/lib/hobo_fields/enum_string.rb +16 -16
- data/lib/hobo_fields/field_declaration_dsl.rb +11 -11
- data/lib/hobo_fields/field_spec.rb +19 -19
- data/lib/hobo_fields/fields_declaration.rb +5 -5
- data/lib/hobo_fields/html_string.rb +4 -6
- data/lib/hobo_fields/markdown_string.rb +3 -3
- data/lib/hobo_fields/migration_generator.rb +86 -66
- data/lib/hobo_fields/model_extensions.rb +43 -40
- data/lib/hobo_fields/password_string.rb +5 -5
- data/lib/hobo_fields/text.rb +9 -9
- data/lib/hobo_fields/textile_string.rb +3 -12
- data/lib/hobo_fields.rb +33 -32
- data/{generators → rails_generators}/hobo_migration/hobo_migration_generator.rb +46 -20
- data/{generators → rails_generators}/hobo_migration/templates/migration.rb +0 -0
- data/rails_generators/hobofield_model/USAGE +29 -0
- data/rails_generators/hobofield_model/hobofield_model_generator.rb +38 -0
- data/rails_generators/hobofield_model/templates/fixtures.yml.erb +19 -0
- data/rails_generators/hobofield_model/templates/model.rb.erb +10 -0
- data/rails_generators/hobofield_model/templates/test.rb.erb +8 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/hobofields.rdoctest +65 -28
- data/test/hobofields_api.rdoctest +28 -27
- data/test/migration_generator.rdoctest +75 -43
- data/test/rich_types.rdoctest +26 -26
- data/test/test_generator_helper.rb +29 -0
- data/test/test_hobofield_model_generator.rb +65 -0
- metadata +29 -10
@@ -1,67 +1,78 @@
|
|
1
1
|
module HoboFields
|
2
|
-
|
2
|
+
|
3
3
|
class MigrationGeneratorError < RuntimeError; end
|
4
|
-
|
4
|
+
|
5
5
|
class MigrationGenerator
|
6
|
-
|
6
|
+
|
7
7
|
@ignore_models = []
|
8
8
|
@ignore_tables = []
|
9
|
-
|
9
|
+
|
10
10
|
class << self
|
11
11
|
attr_accessor :ignore_models, :ignore_tables
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def self.run(renames={})
|
15
15
|
g = MigrationGenerator.new
|
16
16
|
g.renames = renames
|
17
17
|
g.generate
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def initialize(ambiguity_resolver=nil)
|
21
21
|
@ambiguity_resolver = ambiguity_resolver
|
22
22
|
@drops = []
|
23
23
|
@renames = nil
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
attr_accessor :renames
|
27
|
-
|
27
|
+
|
28
|
+
|
28
29
|
def load_rails_models
|
29
30
|
if defined? RAILS_ROOT
|
30
|
-
Dir
|
31
|
-
|
31
|
+
Dir["#{RAILS_ROOT}/app/models/**/[a-z0-9_]*.rb"].each do |f|
|
32
|
+
_, filename = *f.match(%r{/app/models/([_a-z0-9/]*).rb$})
|
33
|
+
filename.camelize.constantize
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
35
|
-
|
36
|
-
|
37
|
+
|
38
|
+
|
37
39
|
# Returns an array of model classes that *directly* extend
|
38
40
|
# ActiveRecord::Base, excluding anything in the CGI module
|
39
41
|
def table_model_classes
|
40
42
|
load_rails_models
|
41
43
|
ActiveRecord::Base.send(:subclasses).where.descends_from_active_record?.reject {|c| c.name.starts_with?("CGI::") }
|
42
|
-
end
|
43
|
-
|
44
|
-
|
45
|
-
def connection
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def self.connection
|
46
48
|
ActiveRecord::Base.connection
|
47
49
|
end
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
50
|
+
def connection; self.class.connection; end
|
51
|
+
|
52
|
+
|
53
|
+
def self.fix_native_types(types)
|
54
|
+
case connection.class.name
|
55
|
+
when /mysql/i
|
56
|
+
types[:integer][:limit] = 11
|
57
|
+
end
|
58
|
+
types
|
52
59
|
end
|
53
|
-
|
54
|
-
|
60
|
+
|
61
|
+
def self.native_types
|
62
|
+
@native_types ||= fix_native_types connection.native_database_types
|
63
|
+
end
|
64
|
+
def native_types; self.class.native_types; end
|
65
|
+
|
55
66
|
# Returns an array of model classes and an array of table names
|
56
67
|
# that generation needs to take into account
|
57
68
|
def models_and_tables
|
58
69
|
ignore_model_names = MigrationGenerator.ignore_models.map &it.to_s.underscore
|
59
70
|
models = table_model_classes.select { |m| m < HoboFields::ModelExtensions && m.name.underscore.not_in?(ignore_model_names) }
|
60
|
-
db_tables = connection.tables - MigrationGenerator.ignore_tables.*.to_s
|
71
|
+
db_tables = connection.tables - MigrationGenerator.ignore_tables.*.to_s
|
61
72
|
[models, db_tables]
|
62
73
|
end
|
63
|
-
|
64
|
-
|
74
|
+
|
75
|
+
|
65
76
|
# return a hash of table renames and modifies the passed arrays so
|
66
77
|
# that renamed tables are no longer listed as to_create or to_drop
|
67
78
|
def extract_table_renames!(to_create, to_drop)
|
@@ -72,7 +83,7 @@ module HoboFields
|
|
72
83
|
renames.each_pair do |old_name, new_name|
|
73
84
|
new_name = new_name[:table_name] if new_name.is_a?(Hash)
|
74
85
|
next unless new_name
|
75
|
-
|
86
|
+
|
76
87
|
if to_create.delete(new_name.to_s) && to_drop.delete(old_name.to_s)
|
77
88
|
to_rename[old_name.to_s] = new_name.to_s
|
78
89
|
else
|
@@ -80,7 +91,7 @@ module HoboFields
|
|
80
91
|
end
|
81
92
|
end
|
82
93
|
to_rename
|
83
|
-
|
94
|
+
|
84
95
|
elsif @ambiguity_resolver
|
85
96
|
@ambiguity_resolver.extract_renames!(to_create, to_drop, "table")
|
86
97
|
|
@@ -88,8 +99,8 @@ module HoboFields
|
|
88
99
|
raise MigrationGeneratorError, "Unable to resolve migration ambiguities"
|
89
100
|
end
|
90
101
|
end
|
91
|
-
|
92
|
-
|
102
|
+
|
103
|
+
|
93
104
|
def extract_column_renames!(to_add, to_remove, table_name)
|
94
105
|
if renames
|
95
106
|
to_rename = {}
|
@@ -106,7 +117,7 @@ module HoboFields
|
|
106
117
|
end
|
107
118
|
end
|
108
119
|
to_rename
|
109
|
-
|
120
|
+
|
110
121
|
elsif @ambiguity_resolver
|
111
122
|
@ambiguity_resolver.extract_renames!(to_add, to_remove, "column", "#{table_name}.")
|
112
123
|
|
@@ -114,19 +125,26 @@ module HoboFields
|
|
114
125
|
raise MigrationGeneratorError, "Unable to resolve migration ambiguities in table #{table_name}"
|
115
126
|
end
|
116
127
|
end
|
117
|
-
|
118
128
|
|
129
|
+
|
130
|
+
def always_ignore_tables
|
131
|
+
sessions_table = CGI::Session::ActiveRecordStore::Session.table_name if
|
132
|
+
ActionController::Base.session_store == CGI::Session::ActiveRecordStore
|
133
|
+
['schema_info', 'schema_migrations', sessions_table].compact
|
134
|
+
end
|
135
|
+
|
136
|
+
|
119
137
|
def generate
|
120
138
|
models, db_tables = models_and_tables
|
121
139
|
models_by_table_name = models.index_by {|m| m.table_name}
|
122
140
|
model_table_names = models.*.table_name
|
123
141
|
|
124
142
|
to_create = model_table_names - db_tables
|
125
|
-
to_drop = db_tables - model_table_names -
|
143
|
+
to_drop = db_tables - model_table_names - always_ignore_tables
|
126
144
|
to_change = model_table_names
|
127
|
-
|
145
|
+
|
128
146
|
to_rename = extract_table_renames!(to_create, to_drop)
|
129
|
-
|
147
|
+
|
130
148
|
renames = to_rename.map do |old_name, new_name|
|
131
149
|
"rename_table :#{old_name}, :#{new_name}"
|
132
150
|
end * "\n"
|
@@ -147,7 +165,7 @@ module HoboFields
|
|
147
165
|
undo_creates = to_create.map do |t|
|
148
166
|
"drop_table :#{t}"
|
149
167
|
end * "\n"
|
150
|
-
|
168
|
+
|
151
169
|
changes = []
|
152
170
|
undo_changes = []
|
153
171
|
to_change.each do |t|
|
@@ -159,7 +177,7 @@ module HoboFields
|
|
159
177
|
undo_changes << undo
|
160
178
|
end
|
161
179
|
end
|
162
|
-
|
180
|
+
|
163
181
|
up = [renames, drops, creates, changes].flatten.reject(&:blank?) * "\n\n"
|
164
182
|
down = [undo_changes, undo_renames, undo_drops, undo_creates].flatten.reject(&:blank?) * "\n\n"
|
165
183
|
|
@@ -172,19 +190,19 @@ module HoboFields
|
|
172
190
|
model.field_specs.values.sort_by{|f| f.position}.map {|f| create_field(f, longest_field_name)} +
|
173
191
|
["end"]) * "\n"
|
174
192
|
end
|
175
|
-
|
193
|
+
|
176
194
|
def create_field(field_spec, field_name_width)
|
177
195
|
args = [field_spec.name.inspect] + format_options(field_spec.options, field_spec.sql_type)
|
178
196
|
" t.%-*s %s" % [field_name_width, field_spec.sql_type, args.join(', ')]
|
179
197
|
end
|
180
|
-
|
198
|
+
|
181
199
|
def change_table(model, current_table_name)
|
182
200
|
new_table_name = model.table_name
|
183
|
-
|
201
|
+
|
184
202
|
db_columns = model.connection.columns(current_table_name).index_by{|c|c.name} - [model.primary_key]
|
185
203
|
model_column_names = model.field_specs.keys.*.to_s
|
186
204
|
db_column_names = db_columns.keys.*.to_s
|
187
|
-
|
205
|
+
|
188
206
|
to_add = model_column_names - db_column_names
|
189
207
|
to_remove = db_column_names - model_column_names - [model.primary_key.to_sym]
|
190
208
|
|
@@ -193,14 +211,14 @@ module HoboFields
|
|
193
211
|
db_column_names -= to_rename.keys
|
194
212
|
db_column_names |= to_rename.values
|
195
213
|
to_change = db_column_names & model_column_names
|
196
|
-
|
214
|
+
|
197
215
|
renames = to_rename.map do |old_name, new_name|
|
198
216
|
"rename_column :#{new_table_name}, :#{old_name}, :#{new_name}"
|
199
217
|
end
|
200
218
|
undo_renames = to_rename.map do |old_name, new_name|
|
201
219
|
"rename_column :#{new_table_name}, :#{new_name}, :#{old_name}"
|
202
220
|
end
|
203
|
-
|
221
|
+
|
204
222
|
to_add = to_add.sort_by {|c| model.field_specs[c].position }
|
205
223
|
adds = to_add.map do |c|
|
206
224
|
spec = model.field_specs[c]
|
@@ -210,14 +228,14 @@ module HoboFields
|
|
210
228
|
undo_adds = to_add.map do |c|
|
211
229
|
"remove_column :#{new_table_name}, :#{c}"
|
212
230
|
end
|
213
|
-
|
231
|
+
|
214
232
|
removes = to_remove.map do |c|
|
215
233
|
"remove_column :#{new_table_name}, :#{c}"
|
216
234
|
end
|
217
235
|
undo_removes = to_remove.map do |c|
|
218
236
|
revert_column(current_table_name, c)
|
219
237
|
end
|
220
|
-
|
238
|
+
|
221
239
|
old_names = to_rename.invert
|
222
240
|
changes = []
|
223
241
|
undo_changes = []
|
@@ -227,42 +245,44 @@ module HoboFields
|
|
227
245
|
spec = model.field_specs[c]
|
228
246
|
if spec.different_to?(col)
|
229
247
|
change_spec = {}
|
230
|
-
change_spec[:limit] = spec.limit unless spec.limit.nil?
|
248
|
+
change_spec[:limit] = spec.limit unless spec.limit.nil? && col.limit.nil?
|
231
249
|
change_spec[:precision] = spec.precision unless spec.precision.nil?
|
232
250
|
change_spec[:scale] = spec.scale unless spec.scale.nil?
|
233
|
-
change_spec[:null] =
|
251
|
+
change_spec[:null] = spec.null unless spec.null && col.null
|
234
252
|
change_spec[:default] = spec.default unless spec.default.nil? && col.default.nil?
|
235
|
-
|
236
|
-
changes << "change_column :#{new_table_name}, :#{c}, " +
|
237
|
-
([":#{spec.sql_type}"] + format_options(change_spec, spec.sql_type)).join(", ")
|
253
|
+
|
254
|
+
changes << "change_column :#{new_table_name}, :#{c}, " +
|
255
|
+
([":#{spec.sql_type}"] + format_options(change_spec, spec.sql_type, true)).join(", ")
|
238
256
|
back = change_column_back(current_table_name, col_name)
|
239
257
|
undo_changes << back unless back.blank?
|
240
258
|
else
|
241
259
|
nil
|
242
260
|
end
|
243
261
|
end.compact
|
244
|
-
|
262
|
+
|
245
263
|
[(renames + adds + removes + changes) * "\n",
|
246
264
|
(undo_renames + undo_adds + undo_removes + undo_changes) * "\n"]
|
247
265
|
end
|
248
|
-
|
249
|
-
|
250
|
-
def format_options(options, type)
|
266
|
+
|
267
|
+
|
268
|
+
def format_options(options, type, changing=false)
|
251
269
|
options.map do |k, v|
|
252
|
-
|
253
|
-
|
254
|
-
|
270
|
+
unless changing
|
271
|
+
next if k == :limit && (type == :decimal || v == native_types[type][:limit])
|
272
|
+
next if k == :null && v == true
|
273
|
+
end
|
274
|
+
"#{k.inspect} => #{v.inspect}"
|
255
275
|
end.compact
|
256
276
|
end
|
257
|
-
|
258
|
-
|
277
|
+
|
278
|
+
|
259
279
|
def revert_table(table)
|
260
280
|
res = StringIO.new
|
261
281
|
ActiveRecord::SchemaDumper.send(:new, ActiveRecord::Base.connection).send(:table, table, res)
|
262
282
|
res.string.strip.gsub("\n ", "\n")
|
263
283
|
end
|
264
|
-
|
265
|
-
|
284
|
+
|
285
|
+
|
266
286
|
def column_options_from_reverted_table(table, column)
|
267
287
|
revert = revert_table(table)
|
268
288
|
if (md = revert.match(/\s*t\.column\s+"#{column}",\s+(:[a-zA-Z0-9_]+)(?:,\s+(.*?)$)?/m))
|
@@ -275,19 +295,19 @@ module HoboFields
|
|
275
295
|
end
|
276
296
|
[type, options]
|
277
297
|
end
|
278
|
-
|
279
|
-
|
298
|
+
|
299
|
+
|
280
300
|
def change_column_back(table, column)
|
281
301
|
type, options = column_options_from_reverted_table(table, column)
|
282
302
|
"change_column :#{table}, :#{column}, #{type}#{', ' + options.strip if options}"
|
283
303
|
end
|
284
|
-
|
304
|
+
|
285
305
|
|
286
306
|
def revert_column(table, column)
|
287
307
|
type, options = column_options_from_reverted_table(table, column)
|
288
308
|
"add_column :#{table}, :#{column}, #{type}#{', ' + options.strip if options}"
|
289
|
-
end
|
290
|
-
|
309
|
+
end
|
310
|
+
|
291
311
|
end
|
292
|
-
|
312
|
+
|
293
313
|
end
|
@@ -1,42 +1,43 @@
|
|
1
1
|
module HoboFields
|
2
|
-
|
2
|
+
|
3
3
|
ModelExtensions = classy_module do
|
4
|
-
|
5
|
-
|
4
|
+
|
5
|
+
|
6
6
|
# attr_types holds the type class for any attribute reader (i.e. getter
|
7
7
|
# method) that returns rich-types
|
8
8
|
inheriting_cattr_reader :attr_types => HashWithIndifferentAccess.new
|
9
|
-
|
9
|
+
inheriting_cattr_reader :attr_order => []
|
10
|
+
|
10
11
|
# field_specs holds FieldSpec objects for every declared
|
11
12
|
# field. Note that attribute readers are created (by ActiveRecord)
|
12
13
|
# for all fields, so there is also an entry for the field in
|
13
14
|
# attr_types. This is redundant but simplifies the implementation
|
14
15
|
# and speeds things up a little.
|
15
16
|
inheriting_cattr_reader :field_specs => HashWithIndifferentAccess.new
|
16
|
-
|
17
|
-
|
17
|
+
|
18
|
+
|
18
19
|
def self.inherited(klass)
|
19
20
|
fields do |f|
|
20
21
|
f.field(inheritance_column, :string)
|
21
22
|
end
|
22
23
|
end
|
23
|
-
|
24
|
+
|
24
25
|
|
25
26
|
def self.field_specs
|
26
27
|
@field_specs ||= HashWithIndifferentAccess.new
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
+
|
30
31
|
private
|
31
|
-
|
32
|
+
|
32
33
|
# Declares that a virtual field that has a rich type (e.g. created
|
33
34
|
# by attr_accessor :foo, :type => :email_address) should be subject
|
34
35
|
# to validation (note that the rich types know how to validate themselves)
|
35
36
|
def self.validate_virtual_field(*args)
|
36
37
|
validates_each(*args) {|record, field, value| msg = value.validate and record.errors.add(field, msg) if value.respond_to?(:validate) }
|
37
38
|
end
|
38
|
-
|
39
|
-
|
39
|
+
|
40
|
+
|
40
41
|
# This adds a ":type => t" option to attr_accessor, where t is
|
41
42
|
# either a class or a symbolic name of a rich type. If this option
|
42
43
|
# is given, the setter will wrap values that are not of the right
|
@@ -46,7 +47,7 @@ module HoboFields
|
|
46
47
|
type = options.delete(:type)
|
47
48
|
attrs << options unless options.empty?
|
48
49
|
attr_accessor_without_rich_types(*attrs)
|
49
|
-
|
50
|
+
|
50
51
|
if type
|
51
52
|
type = HoboFields.to_class(type)
|
52
53
|
attrs.each do |attr|
|
@@ -60,24 +61,25 @@ module HoboFields
|
|
60
61
|
end
|
61
62
|
end
|
62
63
|
end
|
63
|
-
|
64
|
-
|
64
|
+
|
65
|
+
|
65
66
|
# Extend belongs_to so that it creates a FieldSpec for the foreign key
|
66
67
|
def self.belongs_to_with_field_declarations(name, options={}, &block)
|
67
|
-
res = belongs_to_without_field_declarations(name, options, &block)
|
68
|
-
refl = reflections[name.to_sym]
|
69
|
-
fkey = refl.primary_key_name
|
70
68
|
column_options = {}
|
71
|
-
column_options[:null] = options
|
72
|
-
|
73
|
-
|
74
|
-
|
69
|
+
column_options[:null] = options.delete(:null) if options.has_key?(:null)
|
70
|
+
|
71
|
+
returning belongs_to_without_field_declarations(name, options, &block) do
|
72
|
+
refl = reflections[name.to_sym]
|
73
|
+
fkey = refl.primary_key_name
|
74
|
+
declare_field(fkey.to_sym, :integer, column_options)
|
75
|
+
declare_polymorphic_type_field(name, column_options) if refl.options[:polymorphic]
|
76
|
+
end
|
75
77
|
end
|
76
78
|
class << self
|
77
79
|
alias_method_chain :belongs_to, :field_declarations
|
78
80
|
end
|
79
|
-
|
80
|
-
|
81
|
+
|
82
|
+
|
81
83
|
# Declares the "foo_type" field that accompanies the "foo_id"
|
82
84
|
# field for a polyorphic belongs_to
|
83
85
|
def self.declare_polymorphic_type_field(name, column_options)
|
@@ -87,8 +89,8 @@ module HoboFields
|
|
87
89
|
# never_show(type_col)
|
88
90
|
# That needs doing somewhere
|
89
91
|
end
|
90
|
-
|
91
|
-
|
92
|
+
|
93
|
+
|
92
94
|
# Declare a rich-type for any attribute (i.e. getter method). This
|
93
95
|
# does not effect the attribute in any way - it just records the
|
94
96
|
# metadata.
|
@@ -102,14 +104,15 @@ module HoboFields
|
|
102
104
|
# callback, allowing custom metadata to be added to field
|
103
105
|
# declarations.
|
104
106
|
def self.declare_field(name, type, *args)
|
105
|
-
options = args.extract_options!
|
107
|
+
options = args.extract_options!
|
106
108
|
try.field_added(name, type, args, options)
|
107
109
|
add_validations_for_field(name, type, args, options)
|
108
110
|
declare_attr_type(name, type) unless HoboFields.plain_type?(type)
|
109
111
|
field_specs[name] = FieldSpec.new(self, name, type, options)
|
112
|
+
attr_order << name unless name.in?(attr_order)
|
110
113
|
end
|
111
|
-
|
112
|
-
|
114
|
+
|
115
|
+
|
113
116
|
# Add field validations according to arguments and options in the
|
114
117
|
# field declaration
|
115
118
|
def self.add_validations_for_field(name, type, args, options)
|
@@ -124,8 +127,8 @@ module HoboFields
|
|
124
127
|
end
|
125
128
|
end
|
126
129
|
end
|
127
|
-
|
128
|
-
|
130
|
+
|
131
|
+
|
129
132
|
# Extended version of the acts_as_list declaration that
|
130
133
|
# automatically delcares the 'position' field
|
131
134
|
def self.acts_as_list_with_field_declaration(options = {})
|
@@ -133,7 +136,7 @@ module HoboFields
|
|
133
136
|
acts_as_list_without_field_declaration(options)
|
134
137
|
end
|
135
138
|
|
136
|
-
|
139
|
+
|
137
140
|
# Returns the type (a class) for a given field or association. If
|
138
141
|
# the association is a collection (has_many or habtm) return the
|
139
142
|
# AssociationReflection instead
|
@@ -141,27 +144,27 @@ module HoboFields
|
|
141
144
|
if attr_types.nil? && self != self.name.constantize
|
142
145
|
raise RuntimeError, "attr_types called on a stale class object (#{self.name}). Avoid storing persistent refereces to classes"
|
143
146
|
end
|
144
|
-
|
147
|
+
|
145
148
|
attr_types[name] or
|
146
|
-
|
149
|
+
|
147
150
|
if (refl = reflections[name.to_sym])
|
148
|
-
if refl.macro.in?([:has_one, :belongs_to])
|
151
|
+
if refl.macro.in?([:has_one, :belongs_to]) && !refl.options[:polymorphic]
|
149
152
|
refl.klass
|
150
153
|
else
|
151
154
|
refl
|
152
155
|
end
|
153
156
|
end or
|
154
|
-
|
157
|
+
|
155
158
|
(col = column(name.to_s) and HoboFields::PLAIN_TYPES[col.type] || col.klass)
|
156
159
|
end
|
157
|
-
|
158
|
-
|
159
|
-
# Return the entry from #columns for the named column
|
160
|
+
|
161
|
+
|
162
|
+
# Return the entry from #columns for the named column
|
160
163
|
def self.column(name)
|
161
164
|
name = name.to_s
|
162
|
-
columns.find {|c| c.name == name }
|
165
|
+
columns.find {|c| c.name == name }
|
163
166
|
end
|
164
|
-
|
167
|
+
|
165
168
|
class << self
|
166
169
|
alias_method_chain :acts_as_list, :field_declaration if defined?(ActiveRecord::Acts::List)
|
167
170
|
alias_method_chain :attr_accessor, :rich_types
|
data/lib/hobo_fields/text.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
module HoboFields
|
2
|
-
|
2
|
+
|
3
3
|
class Text < String
|
4
|
-
|
4
|
+
|
5
5
|
HTML_ESCAPE = { '&' => '&', '"' => '"', '>' => '>', '<' => '<' }
|
6
|
-
|
6
|
+
|
7
7
|
COLUMN_TYPE = :text
|
8
|
-
|
9
|
-
def to_html
|
10
|
-
gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }.gsub("\n", "<br
|
8
|
+
|
9
|
+
def to_html(xmldoctype = true)
|
10
|
+
gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }.gsub("\n", "<br#{xmldoctype ? ' /' : ''}>\n")
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
HoboFields.register_type(:text, self)
|
14
|
-
|
14
|
+
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'redcloth'
|
2
2
|
|
3
3
|
module HoboFields
|
4
|
-
|
4
|
+
|
5
5
|
class TextileString < HoboFields::Text
|
6
6
|
|
7
|
-
def to_html
|
7
|
+
def to_html(xmldoctype = true)
|
8
8
|
if blank?
|
9
9
|
""
|
10
10
|
else
|
@@ -12,18 +12,9 @@ module HoboFields
|
|
12
12
|
textilized.hard_breaks = true if textilized.respond_to?("hard_breaks=")
|
13
13
|
textilized.to_html
|
14
14
|
end
|
15
|
-
end
|
15
|
+
end
|
16
16
|
|
17
17
|
HoboFields.register_type(:textile, self)
|
18
18
|
end
|
19
19
|
|
20
20
|
end
|
21
|
-
|
22
|
-
class RedCloth
|
23
|
-
# Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet.
|
24
|
-
# http://code.whytheluckystiff.net/redcloth/changeset/128
|
25
|
-
def hard_break( text )
|
26
|
-
text.gsub!( /(.)\n(?!\n|\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks && RedCloth::VERSION == "3.0.4"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|