nanoc 4.0.0b3 → 4.0.0b4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/Gemfile.lock +4 -2
  4. data/NEWS.md +10 -0
  5. data/TODO.md +15 -0
  6. data/lib/nanoc/base.rb +4 -27
  7. data/lib/nanoc/base/checksummer.rb +69 -19
  8. data/lib/nanoc/base/compilation/compiler.rb +14 -12
  9. data/lib/nanoc/base/compilation/compiler_dsl.rb +2 -0
  10. data/lib/nanoc/base/compilation/filter.rb +4 -2
  11. data/lib/nanoc/base/compilation/outdatedness_checker.rb +7 -7
  12. data/lib/nanoc/base/compilation/rule.rb +5 -6
  13. data/lib/nanoc/base/compilation/rule_context.rb +16 -34
  14. data/lib/nanoc/base/compilation/rule_memory_calculator.rb +3 -3
  15. data/lib/nanoc/base/compilation/rules_collection.rb +4 -10
  16. data/lib/nanoc/base/context.rb +2 -0
  17. data/lib/nanoc/base/core_ext/array.rb +0 -10
  18. data/lib/nanoc/base/core_ext/hash.rb +0 -10
  19. data/lib/nanoc/base/core_ext/pathname.rb +0 -9
  20. data/lib/nanoc/base/core_ext/string.rb +0 -10
  21. data/lib/nanoc/base/entities.rb +5 -0
  22. data/lib/nanoc/base/entities/content.rb +86 -0
  23. data/lib/nanoc/base/entities/document.rb +56 -0
  24. data/lib/nanoc/base/{source_data → entities}/identifier.rb +12 -1
  25. data/lib/nanoc/base/entities/layout.rb +8 -0
  26. data/lib/nanoc/base/{pattern.rb → entities/pattern.rb} +0 -0
  27. data/lib/nanoc/base/errors.rb +2 -1
  28. data/lib/nanoc/base/result_data/item_rep.rb +13 -278
  29. data/lib/nanoc/base/services.rb +5 -0
  30. data/lib/nanoc/base/services/executor.rb +141 -0
  31. data/lib/nanoc/base/services/item_rep_writer.rb +40 -0
  32. data/lib/nanoc/base/{notification_center.rb → services/notification_center.rb} +0 -0
  33. data/lib/nanoc/base/services/recording_executor.rb +41 -0
  34. data/lib/nanoc/base/{temp_filename_factory.rb → services/temp_filename_factory.rb} +0 -0
  35. data/lib/nanoc/base/source_data/code_snippet.rb +0 -6
  36. data/lib/nanoc/base/source_data/data_source.rb +4 -3
  37. data/lib/nanoc/base/source_data/item.rb +23 -213
  38. data/lib/nanoc/base/source_data/site.rb +0 -1
  39. data/lib/nanoc/base/views.rb +18 -0
  40. data/lib/nanoc/base/views/config.rb +1 -1
  41. data/lib/nanoc/base/views/item.rb +8 -73
  42. data/lib/nanoc/base/views/item_rep.rb +9 -0
  43. data/lib/nanoc/base/views/item_rep_collection.rb +17 -0
  44. data/lib/nanoc/base/views/layout.rb +1 -40
  45. data/lib/nanoc/base/views/mixins/document.rb +76 -0
  46. data/lib/nanoc/base/views/mixins/mutable_document.rb +22 -0
  47. data/lib/nanoc/base/views/mutable_identifiable_collection.rb +1 -1
  48. data/lib/nanoc/base/views/mutable_item.rb +1 -18
  49. data/lib/nanoc/base/views/mutable_item_collection.rb +6 -2
  50. data/lib/nanoc/base/views/mutable_layout.rb +1 -8
  51. data/lib/nanoc/cli/commands/compile.rb +1 -2
  52. data/lib/nanoc/cli/commands/create-site.rb +5 -5
  53. data/lib/nanoc/cli/commands/show-data.rb +11 -1
  54. data/lib/nanoc/data_sources/filesystem.rb +17 -10
  55. data/lib/nanoc/helpers/capturing.rb +1 -2
  56. data/lib/nanoc/helpers/filtering.rb +13 -1
  57. data/lib/nanoc/helpers/rendering.rb +4 -2
  58. data/lib/nanoc/version.rb +1 -1
  59. data/test/base/core_ext/array_spec.rb +0 -7
  60. data/test/base/core_ext/hash_spec.rb +0 -13
  61. data/test/base/core_ext/pathname_spec.rb +0 -33
  62. data/test/base/core_ext/string_spec.rb +0 -10
  63. data/test/base/test_compiler_dsl.rb +3 -3
  64. data/test/base/test_data_source.rb +2 -2
  65. data/test/base/test_item.rb +5 -129
  66. data/test/base/test_item_rep.rb +26 -558
  67. data/test/base/test_layout.rb +2 -26
  68. data/test/base/test_rule.rb +3 -3
  69. data/test/base/test_rule_context.rb +34 -15
  70. data/test/data_sources/test_filesystem.rb +2 -2
  71. data/test/data_sources/test_filesystem_unified.rb +39 -33
  72. data/test/extra/checking/checks/test_html.rb +0 -1
  73. data/test/extra/checking/checks/test_mixed_content.rb +3 -3
  74. data/test/extra/deployers/test_fog.rb +24 -24
  75. data/test/filters/test_less.rb +4 -4
  76. data/test/filters/test_sass.rb +10 -5
  77. data/test/filters/test_xsl.rb +6 -0
  78. data/test/helpers/test_capturing.rb +0 -1
  79. data/test/helpers/test_filtering.rb +5 -19
  80. data/test/helpers/test_tagging.rb +6 -6
  81. metadata +18 -11
  82. data/lib/nanoc/base/compilation/item_rep_proxy.rb +0 -109
  83. data/lib/nanoc/base/compilation/item_rep_recorder_proxy.rb +0 -97
  84. data/lib/nanoc/base/source_data/layout.rb +0 -111
  85. data/test/base/checksummer_spec.rb +0 -256
  86. data/test/base/test_item_rep_recorder_proxy.rb +0 -17
@@ -0,0 +1,5 @@
1
+ require_relative 'services/executor'
2
+ require_relative 'services/item_rep_writer'
3
+ require_relative 'services/notification_center'
4
+ require_relative 'services/recording_executor'
5
+ require_relative 'services/temp_filename_factory'
@@ -0,0 +1,141 @@
1
+ module Nanoc
2
+ module Int
3
+ class Executor
4
+ def initialize(compiler)
5
+ @compiler = compiler
6
+ end
7
+
8
+ def filter(rep, filter_name, filter_args = {})
9
+ # Get filter class
10
+ klass = Nanoc::Filter.named(filter_name)
11
+ raise Nanoc::Int::Errors::UnknownFilter.new(filter_name) if klass.nil?
12
+
13
+ # Check whether filter can be applied
14
+ if klass.from_binary? && !rep.binary?
15
+ raise Nanoc::Int::Errors::CannotUseBinaryFilter.new(rep, klass)
16
+ elsif !klass.from_binary? && rep.binary?
17
+ raise Nanoc::Int::Errors::CannotUseTextualFilter.new(rep, klass)
18
+ end
19
+
20
+ begin
21
+ # Notify start
22
+ Nanoc::Int::NotificationCenter.post(:filtering_started, rep, filter_name)
23
+
24
+ # Create filter
25
+ filter = klass.new(assigns_for(rep))
26
+
27
+ # Run filter
28
+ last = rep.content_snapshots[:last]
29
+ source = rep.binary? ? last.filename : last.string
30
+ result = filter.setup_and_run(source, filter_args)
31
+ if klass.to_binary?
32
+ rep.content_snapshots[:last] = Nanoc::Int::BinaryContent.new(filter.output_filename).tap(&:freeze)
33
+ else
34
+ rep.content_snapshots[:last] = Nanoc::Int::TextualContent.new(result).tap(&:freeze)
35
+ end
36
+
37
+ # Check whether file was written
38
+ if klass.to_binary? && !File.file?(filter.output_filename)
39
+ raise "The #{filter_name.inspect} filter did not write anything to the required output file, #{filter.output_filename}."
40
+ end
41
+
42
+ # Create snapshot
43
+ snapshot(rep, rep.content_snapshots[:post] ? :post : :pre, final: false) unless rep.binary?
44
+ ensure
45
+ # Notify end
46
+ Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, filter_name)
47
+ end
48
+ end
49
+
50
+ def layout(rep, layout_identifier, extra_filter_args = nil)
51
+ layout = find_layout(layout_identifier)
52
+ filter_name, filter_args = @compiler.rules_collection.filter_for_layout(layout)
53
+ if filter_name.nil?
54
+ raise Nanoc::Int::Errors::Generic, "Cannot find rule for layout matching #{layout_identifier}"
55
+ end
56
+ filter_args = filter_args.merge(extra_filter_args || {})
57
+
58
+ # Check whether item can be laid out
59
+ raise Nanoc::Int::Errors::CannotLayoutBinaryItem.new(rep) if rep.binary?
60
+
61
+ # Create "pre" snapshot
62
+ if rep.content_snapshots[:post].nil?
63
+ snapshot(rep, :pre, final: true)
64
+ end
65
+
66
+ # Create filter
67
+ klass = Nanoc::Filter.named(filter_name)
68
+ raise Nanoc::Int::Errors::UnknownFilter.new(filter_name) if klass.nil?
69
+ filter = klass.new(assigns_for(rep).merge({ layout: layout }))
70
+
71
+ # Visit
72
+ Nanoc::Int::NotificationCenter.post(:visit_started, layout)
73
+ Nanoc::Int::NotificationCenter.post(:visit_ended, layout)
74
+
75
+ begin
76
+ # Notify start
77
+ Nanoc::Int::NotificationCenter.post(:processing_started, layout)
78
+ Nanoc::Int::NotificationCenter.post(:filtering_started, rep, filter_name)
79
+
80
+ # Layout
81
+ content = layout.content
82
+ arg = content.binary? ? content.filename : content.string
83
+ res = filter.setup_and_run(arg, filter_args)
84
+ rep.content_snapshots[:last] = Nanoc::Int::TextualContent.new(res).tap(&:freeze)
85
+
86
+ # Create "post" snapshot
87
+ snapshot(rep, :post, final: false)
88
+ ensure
89
+ # Notify end
90
+ Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, filter_name)
91
+ Nanoc::Int::NotificationCenter.post(:processing_ended, layout)
92
+ end
93
+ end
94
+
95
+ def snapshot(rep, snapshot_name, params = {})
96
+ is_final = params.fetch(:final, true)
97
+
98
+ unless rep.binary?
99
+ rep.content_snapshots[snapshot_name] = rep.content_snapshots[:last]
100
+ end
101
+
102
+ if snapshot_name == :pre && is_final
103
+ rep.snapshots << [:pre, true]
104
+ end
105
+
106
+ if is_final
107
+ raw_path = rep.raw_path(snapshot: snapshot_name)
108
+ if raw_path
109
+ ItemRepWriter.new.write(rep, raw_path)
110
+ end
111
+ end
112
+ end
113
+
114
+ def assigns_for(rep)
115
+ @compiler.assigns_for(rep)
116
+ end
117
+
118
+ def layouts
119
+ @compiler.site.layouts
120
+ end
121
+
122
+ def find_layout(arg)
123
+ req_id = arg.__nanoc_cleaned_identifier
124
+ layout = layouts.find { |l| l.identifier == req_id }
125
+ return layout if layout
126
+
127
+ if use_globs?
128
+ pat = Nanoc::Int::Pattern.from(arg)
129
+ layout = layouts.find { |l| pat.match?(l.identifier) }
130
+ return layout if layout
131
+ end
132
+
133
+ raise Nanoc::Int::Errors::UnknownLayout.new(arg)
134
+ end
135
+
136
+ def use_globs?
137
+ @compiler.site.config[:string_pattern_type] == 'glob'
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,40 @@
1
+ module Nanoc::Int
2
+ # @api private
3
+ class ItemRepWriter
4
+ TMP_TEXT_ITEMS_DIR = 'text_items'
5
+
6
+ def write(item_rep, raw_path)
7
+ # Create parent directory
8
+ FileUtils.mkdir_p(File.dirname(raw_path))
9
+
10
+ # Check if file will be created
11
+ is_created = !File.file?(raw_path)
12
+
13
+ # Notify
14
+ Nanoc::Int::NotificationCenter.post(
15
+ :will_write_rep, item_rep, raw_path)
16
+
17
+ content = item_rep.content_snapshots[:last]
18
+ if content.binary?
19
+ temp_path = content.filename
20
+ else
21
+ temp_path = temp_filename
22
+ File.write(temp_path, content.string)
23
+ end
24
+
25
+ # Check whether content was modified
26
+ is_modified = is_created || !FileUtils.identical?(raw_path, temp_path)
27
+
28
+ # Write
29
+ FileUtils.cp(temp_path, raw_path) if is_modified
30
+
31
+ # Notify
32
+ Nanoc::Int::NotificationCenter.post(
33
+ :rep_written, item_rep, raw_path, is_created, is_modified)
34
+ end
35
+
36
+ def temp_filename
37
+ Nanoc::Int::TempFilenameFactory.instance.create(TMP_TEXT_ITEMS_DIR)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ module Nanoc
2
+ module Int
3
+ class RecordingExecutor
4
+ attr_reader :rule_memory
5
+
6
+ def initialize
7
+ @rule_memory = []
8
+ end
9
+
10
+ def filter(rep, filter_name, filter_args = {})
11
+ @rule_memory << [:filter, filter_name, filter_args]
12
+ end
13
+
14
+ def layout(rep, layout_identifier, extra_filter_args = nil)
15
+ if extra_filter_args
16
+ @rule_memory << [:layout, layout_identifier, extra_filter_args]
17
+ else
18
+ @rule_memory << [:layout, layout_identifier]
19
+ end
20
+ end
21
+
22
+ def snapshot(rep, snapshot_name, params = {})
23
+ @rule_memory << [:snapshot, snapshot_name, params]
24
+
25
+ # Count
26
+ existing = Set.new
27
+ names = @rule_memory.select { |r| r[0] == :snapshot }.map { |r| r[1] }
28
+ names.each do |n|
29
+ if existing.include?(n)
30
+ raise Nanoc::Int::Errors::CannotCreateMultipleSnapshotsWithSameName.new(@item_rep, snapshot_name)
31
+ end
32
+ existing << n
33
+ end
34
+ end
35
+
36
+ def record_write(rep, path)
37
+ @rule_memory << [:write, path]
38
+ end
39
+ end
40
+ end
41
+ end
@@ -44,11 +44,5 @@ module Nanoc::Int
44
44
  def inspect
45
45
  "<#{self.class} filename=\"#{filename}\">"
46
46
  end
47
-
48
- # @return [String] The checksum for this object. If its contents change,
49
- # the checksum will change as well.
50
- def __nanoc_checksum
51
- Nanoc::Int::Checksummer.calc(self)
52
- end
53
47
  end
54
48
  end
@@ -143,7 +143,7 @@ module Nanoc
143
143
  # Creates a new in-memory item instance. This is intended for use within
144
144
  # the {#items} method.
145
145
  #
146
- # @param [String] raw_content_or_raw_filename The uncompiled item content
146
+ # @param [String] content The uncompiled item content
147
147
  # (if it is a textual item) or the path to the filename containing the
148
148
  # content (if it is a binary item).
149
149
  #
@@ -155,8 +155,9 @@ module Nanoc
155
155
  #
156
156
  # @option params [Symbol, nil] :binary (true) Whether or not this item is
157
157
  # binary
158
- def new_item(raw_content_or_raw_filename, attributes, identifier, params = {})
159
- Nanoc::Int::Item.new(raw_content_or_raw_filename, attributes, identifier, params)
158
+ def new_item(content, attributes, identifier, params = {})
159
+ content = Nanoc::Int::Content.create(content, params)
160
+ Nanoc::Int::Item.new(content, attributes, identifier)
160
161
  end
161
162
 
162
163
  # Creates a new in-memory layout instance. This is intended for use within
@@ -1,32 +1,9 @@
1
1
  module Nanoc::Int
2
- # Represents a compileable item in a site. It has content and attributes, as
3
- # well as an identifier (which starts and ends with a slash). It can also
4
- # store the modification time to speed up compilation.
5
- #
6
2
  # @api private
7
- class Item
8
- extend Nanoc::Int::Memoization
9
-
10
- # @return [Hash] This item's attributes
11
- attr_accessor :attributes
12
-
13
- # @return [Nanoc::Identifier] This item's identifier
14
- attr_accessor :identifier
15
-
3
+ class Item < ::Nanoc::Int::Document
16
4
  # @return [Array<Nanoc::Int::ItemRep>] This item’s list of item reps
17
5
  attr_reader :reps
18
6
 
19
- # @return [String] This item's raw, uncompiled content of this item (only
20
- # available for textual items)
21
- attr_reader :raw_content
22
-
23
- # @return [String] The filename pointing to the file containing this
24
- # item’s content
25
- attr_reader :raw_filename
26
-
27
- # @return [Nanoc::Int::Site] The site this item belongs to
28
- attr_accessor :site
29
-
30
7
  # @return [Nanoc::Int::Item, nil] The parent item of this item. This can be
31
8
  # nil even for non-root items.
32
9
  attr_accessor :parent
@@ -34,148 +11,19 @@ module Nanoc::Int
34
11
  # @return [Array<Nanoc::Int::Item>] The child items of this item
35
12
  attr_accessor :children
36
13
 
37
- # Creates a new item with the given content or filename, attributes and
38
- # identifier.
39
- #
40
- # @param [String] raw_content_or_raw_filename The uncompiled item content
41
- # (if it is a textual item) or the path to the filename containing the
42
- # content (if it is a binary item).
43
- #
44
- # @param [Hash] attributes A hash containing this item's attributes.
45
- #
46
- # @param [String] identifier This item's identifier.
47
- #
48
- # @param [Hash] params Extra parameters.
49
- #
50
- # @option params [Symbol, nil] :binary (true) Whether or not this item is
51
- # binary
52
- def initialize(raw_content_or_raw_filename, attributes, identifier, params = {})
53
- # Parse params
54
- params = params.merge(binary: false) unless params.key?(:binary)
55
-
56
- if raw_content_or_raw_filename.nil?
57
- raise "attempted to create an item with no content/filename (identifier #{identifier})"
58
- end
59
-
60
- # Get type and raw content or raw filename
61
- @is_binary = params[:binary]
62
- if @is_binary
63
- @raw_filename = raw_content_or_raw_filename
64
- else
65
- @raw_filename = attributes[:content_filename]
66
- @raw_content = raw_content_or_raw_filename
67
- end
68
-
69
- # Get rest of params
70
- @attributes = attributes.__nanoc_symbolize_keys_recursively
71
- @identifier = Nanoc::Identifier.from(identifier)
72
-
73
- # Set mtime
74
- @attributes.merge!(mtime: params[:mtime]) if params[:mtime]
14
+ # @see Document#initialize
15
+ def initialize(content, attributes, identifier)
16
+ super
75
17
 
76
- @parent = nil
77
- @children = []
78
-
79
- @reps = []
80
- end
81
-
82
- # Returns the rep with the given name.
83
- #
84
- # @param [Symbol] rep_name The name of the representation to return
85
- #
86
- # @return [Nanoc::Int::ItemRep] The representation with the given name
87
- def rep_named(rep_name)
88
- @reps.find { |r| r.name == rep_name }
18
+ @parent = nil
19
+ @children = []
20
+ @reps = []
21
+ @forced_outdated_status = ForcedOutdatedStatus.new
89
22
  end
90
23
 
91
- # Returns the compiled content from a given representation and a given
92
- # snapshot. This is a convenience method that makes fetching compiled
93
- # content easier.
94
- #
95
- # @option params [String] :rep (:default) The name of the representation
96
- # from which the compiled content should be fetched. By default, the
97
- # compiled content will be fetched from the default representation.
98
- #
99
- # @option params [String] :snapshot The name of the snapshot from which to
100
- # fetch the compiled content. By default, the returned compiled content
101
- # will be the content compiled right before the first layout call (if
102
- # any).
103
- #
104
- # @return [String] The compiled content of the given rep (or the default
105
- # rep if no rep is specified) at the given snapshot (or the default
106
- # snapshot if no snapshot is specified)
107
- #
108
- # @see ItemRep#compiled_content
109
- def compiled_content(params = {})
110
- # Get rep
111
- rep_name = params[:rep] || :default
112
- rep = reps.find { |r| r.name == rep_name }
113
- if rep.nil?
114
- raise Nanoc::Int::Errors::Generic,
115
- "No rep named #{rep_name.inspect} was found."
116
- end
117
-
118
- # Get rep's content
119
- rep.compiled_content(params)
120
- end
121
-
122
- # Returns the path from a given representation. This is a convenience
123
- # method that makes fetching the path of a rep easier.
124
- #
125
- # @option params [String] :rep (:default) The name of the representation
126
- # from which the path should be fetched. By default, the path will be
127
- # fetched from the default representation.
128
- #
129
- # @return [String] The path of the given rep ( or the default rep if no
130
- # rep is specified)
131
- def path(params = {})
132
- rep_name = params[:rep] || :default
133
-
134
- # Get rep
135
- rep = reps.find { |r| r.name == rep_name }
136
- if rep.nil?
137
- raise Nanoc::Int::Errors::Generic,
138
- "No rep named #{rep_name.inspect} was found."
139
- end
140
-
141
- # Get rep's path
142
- rep.path
143
- end
144
-
145
- # Requests the attribute with the given key.
146
- #
147
- # @param [Symbol] key The name of the attribute to fetch
148
- #
149
- # @return [Object] The value of the requested attribute
150
- def [](key)
151
- Nanoc::Int::NotificationCenter.post(:visit_started, self)
152
- Nanoc::Int::NotificationCenter.post(:visit_ended, self)
153
-
154
- @attributes[key]
155
- end
156
-
157
- # Sets the attribute with the given key to the given value.
158
- #
159
- # @param [Symbol] key The name of the attribute to set
160
- #
161
- # @param [Object] value The value of the attribute to set
162
- def []=(key, value)
163
- @attributes[key] = value
164
- end
165
-
166
- # @return [Boolean] True if the item is binary; false if it is not
167
- def binary?
168
- @is_binary
169
- end
170
-
171
- # Returns the type of this object. Will always return `:item`, because
172
- # this is an item. For layouts, this method returns `:layout`.
173
- #
174
- # @api private
175
- #
176
- # @return [Symbol] :item
177
- def type
178
- :item
24
+ def freeze
25
+ super
26
+ @children.freeze
179
27
  end
180
28
 
181
29
  # Returns an object that can be used for uniquely identifying objects.
@@ -184,69 +32,31 @@ module Nanoc::Int
184
32
  #
185
33
  # @return [Object] An unique reference to this object
186
34
  def reference
187
- [type, identifier.to_s]
35
+ [:item, identifier.to_s]
188
36
  end
189
37
 
190
- # Prevents all further modifications to its attributes.
38
+ # Hack to allow a frozen item to still have modifiable frozen status.
191
39
  #
192
- # @return [void]
193
- def freeze
194
- attributes.__nanoc_freeze_recursively
195
- children.freeze
196
- identifier.freeze
197
- raw_filename.freeze if raw_filename
198
- raw_content.freeze if raw_content
199
- end
200
-
201
- def inspect
202
- "<#{self.class} identifier=\"#{identifier}\" binary?=#{self.binary?}>"
203
- end
204
-
205
- # @return [String] The checksum for this object. If its contents change,
206
- # the checksum will change as well.
207
- def __nanoc_checksum
208
- Nanoc::Int::Checksummer.calc(self)
209
- end
210
- memoize :__nanoc_checksum
211
-
212
- def hash
213
- self.class.hash ^ identifier.hash
214
- end
215
-
216
- def eql?(other)
217
- self.class == other.class && identifier == other.identifier
218
- end
219
-
220
- def ==(other)
221
- self.eql?(other)
222
- end
40
+ # FIXME: Remove this.
41
+ class ForcedOutdatedStatus
42
+ attr_accessor :bool
223
43
 
224
- def marshal_dump
225
- [
226
- @is_binary,
227
- @raw_filename,
228
- @raw_content,
229
- @attributes,
230
- @identifier
231
- ]
232
- end
44
+ def initialize
45
+ @bool = false
46
+ end
233
47
 
234
- def marshal_load(source)
235
- @is_binary,
236
- @raw_filename,
237
- @raw_content,
238
- @attributes,
239
- @identifier = *source
48
+ def freeze
49
+ end
240
50
  end
241
51
 
242
52
  # @api private
243
53
  def forced_outdated=(bool)
244
- @forced_outdated = bool
54
+ @forced_outdated_status.bool = bool
245
55
  end
246
56
 
247
57
  # @api private
248
58
  def forced_outdated?
249
- @forced_outdated || false
59
+ @forced_outdated_status.bool
250
60
  end
251
61
  end
252
62
  end