ruby_pptx 0.1.0 → 0.2.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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/README.md +83 -2
  4. data/lib/ruby_pptx/action.rb +12 -4
  5. data/lib/ruby_pptx/autoshape_spec.rb +6 -2
  6. data/lib/ruby_pptx/builder.rb +3 -1
  7. data/lib/ruby_pptx/chart/categories.rb +45 -15
  8. data/lib/ruby_pptx/chart/chart.rb +77 -27
  9. data/lib/ruby_pptx/chart/combo.rb +9 -3
  10. data/lib/ruby_pptx/chart/data.rb +45 -15
  11. data/lib/ruby_pptx/chart/format.rb +229 -76
  12. data/lib/ruby_pptx/chart/workbook_writer.rb +9 -3
  13. data/lib/ruby_pptx/chart/xml_writer.rb +54 -18
  14. data/lib/ruby_pptx/chart/xy_data.rb +68 -22
  15. data/lib/ruby_pptx/dml/color.rb +27 -9
  16. data/lib/ruby_pptx/dml/effect.rb +6 -2
  17. data/lib/ruby_pptx/dml/fill.rb +42 -14
  18. data/lib/ruby_pptx/element_proxy.rb +12 -4
  19. data/lib/ruby_pptx/enum/base.rb +30 -10
  20. data/lib/ruby_pptx/enum/prog_id.rb +3 -1
  21. data/lib/ruby_pptx/geometry.rb +32 -10
  22. data/lib/ruby_pptx/image.rb +27 -9
  23. data/lib/ruby_pptx/length.rb +94 -27
  24. data/lib/ruby_pptx/media.rb +12 -4
  25. data/lib/ruby_pptx/numeric_lengths.rb +34 -9
  26. data/lib/ruby_pptx/opc/oxml.rb +7 -5
  27. data/lib/ruby_pptx/opc/pack_uri.rb +15 -5
  28. data/lib/ruby_pptx/opc/package.rb +97 -31
  29. data/lib/ruby_pptx/opc/serialized.rb +15 -5
  30. data/lib/ruby_pptx/oxml/backend.rb +585 -0
  31. data/lib/ruby_pptx/oxml/chart.rb +112 -42
  32. data/lib/ruby_pptx/oxml/content_model.rb +6 -2
  33. data/lib/ruby_pptx/oxml/dml/color.rb +6 -2
  34. data/lib/ruby_pptx/oxml/dml/fill.rb +6 -2
  35. data/lib/ruby_pptx/oxml/element.rb +138 -101
  36. data/lib/ruby_pptx/oxml/ns.rb +7 -7
  37. data/lib/ruby_pptx/oxml/presentation.rb +9 -3
  38. data/lib/ruby_pptx/oxml/section.rb +3 -1
  39. data/lib/ruby_pptx/oxml/shapes/autoshape.rb +39 -13
  40. data/lib/ruby_pptx/oxml/shapes/groupshape.rb +15 -7
  41. data/lib/ruby_pptx/oxml/shapes/other.rb +47 -16
  42. data/lib/ruby_pptx/oxml/shapes/shared.rb +96 -30
  43. data/lib/ruby_pptx/oxml/simple_types.rb +169 -52
  44. data/lib/ruby_pptx/oxml/slide.rb +24 -8
  45. data/lib/ruby_pptx/oxml/table.rb +39 -13
  46. data/lib/ruby_pptx/oxml/text.rb +37 -15
  47. data/lib/ruby_pptx/oxml/theme.rb +13 -4
  48. data/lib/ruby_pptx/package.rb +9 -3
  49. data/lib/ruby_pptx/parts/chart.rb +6 -2
  50. data/lib/ruby_pptx/parts/image.rb +12 -4
  51. data/lib/ruby_pptx/parts/media.rb +3 -1
  52. data/lib/ruby_pptx/parts/presentation.rb +15 -5
  53. data/lib/ruby_pptx/parts/slide.rb +33 -11
  54. data/lib/ruby_pptx/parts/theme.rb +3 -1
  55. data/lib/ruby_pptx/pattern_matching.rb +6 -2
  56. data/lib/ruby_pptx/presentation.rb +24 -8
  57. data/lib/ruby_pptx/section.rb +30 -10
  58. data/lib/ruby_pptx/shapes/adjustments.rb +9 -3
  59. data/lib/ruby_pptx/shapes/authoring.rb +3 -1
  60. data/lib/ruby_pptx/shapes/base.rb +74 -24
  61. data/lib/ruby_pptx/shapes/freeform.rb +36 -12
  62. data/lib/ruby_pptx/shapes/placeholder.rb +44 -15
  63. data/lib/ruby_pptx/shapes/shape.rb +91 -30
  64. data/lib/ruby_pptx/shapes/shape_tree.rb +66 -22
  65. data/lib/ruby_pptx/slide.rb +123 -41
  66. data/lib/ruby_pptx/table.rb +105 -35
  67. data/lib/ruby_pptx/text/font_metrics.rb +30 -9
  68. data/lib/ruby_pptx/text/text.rb +108 -36
  69. data/lib/ruby_pptx/theme.rb +30 -10
  70. data/lib/ruby_pptx/version.rb +1 -1
  71. data/lib/ruby_pptx.rb +8 -1
  72. metadata +22 -1
@@ -50,7 +50,9 @@ module Pptx
50
50
  attr_reader :blob, :filename
51
51
 
52
52
  class << self
53
- def from_blob(blob, filename = nil) = new(blob, filename)
53
+ def from_blob(blob, filename = nil)
54
+ new(blob, filename)
55
+ end
54
56
 
55
57
  # Load from a path or an IO stream.
56
58
  def from_file(image_file)
@@ -69,18 +71,28 @@ module Pptx
69
71
  end
70
72
 
71
73
  # @return [Symbol] :PNG, :JPEG, :GIF, :BMP, :TIFF or :WMF
72
- def format = header.fetch(:format)
74
+ def format
75
+ header.fetch(:format)
76
+ end
73
77
 
74
78
  # True for a vector image, which has no pixel size of its own and needs a
75
79
  # raster fallback to be placed in a slide.
76
- def vector? = format == :SVG
80
+ def vector?
81
+ format == :SVG
82
+ end
77
83
 
78
84
  # @return [Array(Integer, Integer)] width and height in pixels
79
- def size = [header.fetch(:width), header.fetch(:height)]
85
+ def size
86
+ [header.fetch(:width), header.fetch(:height)]
87
+ end
80
88
 
81
- def width_px = header.fetch(:width)
89
+ def width_px
90
+ header.fetch(:width)
91
+ end
82
92
 
83
- def height_px = header.fetch(:height)
93
+ def height_px
94
+ header.fetch(:height)
95
+ end
84
96
 
85
97
  # @return [Array(Integer, Integer)] horizontal and vertical dots per inch
86
98
  def dpi
@@ -94,9 +106,13 @@ module Pptx
94
106
  end
95
107
  end
96
108
 
97
- def content_type = CONTENT_TYPE_FOR_EXT.fetch(ext)
109
+ def content_type
110
+ CONTENT_TYPE_FOR_EXT.fetch(ext)
111
+ end
98
112
 
99
- def sha1 = @sha1 ||= Digest::SHA1.hexdigest(@blob)
113
+ def sha1
114
+ @sha1 ||= Digest::SHA1.hexdigest(@blob)
115
+ end
100
116
 
101
117
  # Native size in EMU, derived from the pixel size and resolution.
102
118
  #
@@ -109,7 +125,9 @@ module Pptx
109
125
  Length.emu((EMU_PER_INCH * height_px / vert_dpi).to_i)]
110
126
  end
111
127
 
112
- def inspect = "#<Pptx::Image #{format} #{width_px}x#{height_px} #{dpi.join("x")}dpi>"
128
+ def inspect
129
+ "#<Pptx::Image #{format} #{width_px}x#{height_px} #{dpi.join("x")}dpi>"
130
+ end
113
131
 
114
132
  private
115
133
 
@@ -30,16 +30,31 @@ module Pptx
30
30
 
31
31
  class << self
32
32
  # @param emu [Integer] distance in English Metric Units
33
- def emu(emu) = new(emu)
33
+ def emu(emu)
34
+ new(emu)
35
+ end
36
+
37
+ def inches(inches)
38
+ new((inches * EMUS_PER_INCH).to_i)
39
+ end
40
+
41
+ def cm(cm)
42
+ new((cm * EMUS_PER_CM).to_i)
43
+ end
34
44
 
35
- def inches(inches) = new((inches * EMUS_PER_INCH).to_i)
36
- def cm(cm) = new((cm * EMUS_PER_CM).to_i)
37
- def mm(mm) = new((mm * EMUS_PER_MM).to_i)
38
- def pt(points) = new((points * EMUS_PER_PT).to_i)
45
+ def mm(mm)
46
+ new((mm * EMUS_PER_MM).to_i)
47
+ end
48
+
49
+ def pt(points)
50
+ new((points * EMUS_PER_PT).to_i)
51
+ end
39
52
 
40
53
  # Hundredths of a point (1/7200 inch); the unit PowerPoint stores font
41
54
  # sizes in.
42
- def centipoints(centipoints) = new((centipoints * EMUS_PER_CENTIPOINT).to_i)
55
+ def centipoints(centipoints)
56
+ new((centipoints * EMUS_PER_CENTIPOINT).to_i)
57
+ end
43
58
 
44
59
  # Coerce +value+ to a Length, treating a bare Integer as EMU.
45
60
  #
@@ -63,23 +78,48 @@ module Pptx
63
78
  freeze
64
79
  end
65
80
 
66
- def inches = @emu / EMUS_PER_INCH.to_f
67
- def cm = @emu / EMUS_PER_CM.to_f
68
- def mm = @emu / EMUS_PER_MM.to_f
69
- def pt = @emu / EMUS_PER_PT.to_f
81
+ def inches
82
+ @emu / EMUS_PER_INCH.to_f
83
+ end
84
+
85
+ def cm
86
+ @emu / EMUS_PER_CM.to_f
87
+ end
88
+
89
+ def mm
90
+ @emu / EMUS_PER_MM.to_f
91
+ end
92
+
93
+ def pt
94
+ @emu / EMUS_PER_PT.to_f
95
+ end
70
96
 
71
97
  # @return [Integer] whole hundredths of a point, rounded toward negative infinity
72
- def centipoints = @emu / EMUS_PER_CENTIPOINT
98
+ def centipoints
99
+ @emu / EMUS_PER_CENTIPOINT
100
+ end
73
101
 
74
- def to_i = @emu
102
+ def to_i
103
+ @emu
104
+ end
75
105
  alias to_int to_i
76
106
 
77
- def +(other) = Length.new(@emu + Length.coerce(other).emu)
78
- def -(other) = Length.new(@emu - Length.coerce(other).emu)
79
- def -@ = Length.new(-@emu)
107
+ def +(other)
108
+ Length.new(@emu + Length.coerce(other).emu)
109
+ end
110
+
111
+ def -(other)
112
+ Length.new(@emu - Length.coerce(other).emu)
113
+ end
114
+
115
+ def -@
116
+ Length.new(-@emu)
117
+ end
80
118
 
81
119
  # Scaling by a plain number; `length * 2` is twice as long.
82
- def *(factor) = Length.new((@emu * factor).to_i)
120
+ def *(factor)
121
+ Length.new((@emu * factor).to_i)
122
+ end
83
123
 
84
124
  # Deliberately no #coerce, so `2 * length` raises rather than working.
85
125
  #
@@ -96,25 +136,52 @@ module Pptx
96
136
  @emu <=> other.emu
97
137
  end
98
138
 
99
- def ==(other) = (self <=> other)&.zero? || false
139
+ def ==(other)
140
+ (self <=> other)&.zero? || false
141
+ end
100
142
  alias eql? ==
101
143
 
102
- def hash = @emu.hash
144
+ def hash
145
+ @emu.hash
146
+ end
103
147
 
104
- def zero? = @emu.zero?
148
+ def zero?
149
+ @emu.zero?
150
+ end
105
151
 
106
- def to_s = "#{@emu}emu"
152
+ def to_s
153
+ "#{@emu}emu"
154
+ end
107
155
 
108
- def inspect = "#<Pptx::Length #{@emu}emu (#{format("%g", inches)}in)>"
156
+ def inspect
157
+ "#<Pptx::Length #{@emu}emu (#{format("%g", inches)}in)>"
158
+ end
109
159
  end
110
160
 
111
161
  class << self
112
162
  # Convenience constructors, e.g. `Pptx.inches(1.5)`.
113
- def emu(v) = Length.emu(v)
114
- def inches(v) = Length.inches(v)
115
- def cm(v) = Length.cm(v)
116
- def mm(v) = Length.mm(v)
117
- def pt(v) = Length.pt(v)
118
- def centipoints(v) = Length.centipoints(v)
163
+ def emu(v)
164
+ Length.emu(v)
165
+ end
166
+
167
+ def inches(v)
168
+ Length.inches(v)
169
+ end
170
+
171
+ def cm(v)
172
+ Length.cm(v)
173
+ end
174
+
175
+ def mm(v)
176
+ Length.mm(v)
177
+ end
178
+
179
+ def pt(v)
180
+ Length.pt(v)
181
+ end
182
+
183
+ def centipoints(v)
184
+ Length.centipoints(v)
185
+ end
119
186
  end
120
187
  end
@@ -28,7 +28,9 @@ module Pptx
28
28
 
29
29
  attr_reader :blob, :content_type
30
30
 
31
- def self.from_blob(blob, content_type, filename = nil) = new(blob, content_type, filename)
31
+ def self.from_blob(blob, content_type, filename = nil)
32
+ new(blob, content_type, filename)
33
+ end
32
34
 
33
35
  # Load from a path or an IO stream.
34
36
  def self.from_file(movie_file, content_type)
@@ -55,10 +57,16 @@ module Pptx
55
57
  end
56
58
 
57
59
  # The name PowerPoint shows for the shape.
58
- def filename = @source_filename || "movie.#{ext}"
60
+ def filename
61
+ @source_filename || "movie.#{ext}"
62
+ end
59
63
 
60
- def sha1 = @sha1 ||= Digest::SHA1.hexdigest(@blob)
64
+ def sha1
65
+ @sha1 ||= Digest::SHA1.hexdigest(@blob)
66
+ end
61
67
 
62
- def inspect = "#<Pptx::Video #{filename} #{@content_type}>"
68
+ def inspect
69
+ "#<Pptx::Video #{filename} #{@content_type}>"
70
+ end
63
71
  end
64
72
  end
@@ -14,17 +14,42 @@ module Pptx
14
14
  # Prefer the refinement. It is scoped to the file that asks for it, so it
15
15
  # cannot surprise another library that happens to share the process.
16
16
  module NumericLengths
17
- def emu = Pptx::Length.emu(self)
18
- def inches = Pptx::Length.inches(self)
19
- def cm = Pptx::Length.cm(self)
20
- def mm = Pptx::Length.mm(self)
21
- def pt = Pptx::Length.pt(self)
22
- def centipoints = Pptx::Length.centipoints(self)
17
+ def emu
18
+ Pptx::Length.emu(self)
19
+ end
20
+
21
+ def inches
22
+ Pptx::Length.inches(self)
23
+ end
24
+
25
+ def cm
26
+ Pptx::Length.cm(self)
27
+ end
28
+
29
+ def mm
30
+ Pptx::Length.mm(self)
31
+ end
32
+
33
+ def pt
34
+ Pptx::Length.pt(self)
35
+ end
36
+
37
+ def centipoints
38
+ Pptx::Length.centipoints(self)
39
+ end
23
40
 
24
41
  # Spelled out rather than aliased: `import_methods`, which the refinement
25
42
  # uses to share these, cannot carry an alias across.
26
- def inch = inches
27
- def points = pt
28
- def point = pt
43
+ def inch
44
+ inches
45
+ end
46
+
47
+ def points
48
+ pt
49
+ end
50
+
51
+ def point
52
+ pt
53
+ end
29
54
  end
30
55
  end
@@ -20,9 +20,7 @@ module Pptx
20
20
  # to match what python-pptx (and lxml) produce, so packages compare
21
21
  # byte-for-byte.
22
22
  def self.serialize_part_xml(element)
23
- node = element.is_a?(Element) ? element.node : element
24
- body = node.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML |
25
- Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
23
+ body = Element.wrap(element).to_xml
26
24
  %(<?xml version='1.0' encoding='UTF-8' standalone='yes'?>\n#{body})
27
25
  end
28
26
 
@@ -70,7 +68,9 @@ module Pptx
70
68
  optional_attr "TargetMode", type: ST::ST_TargetMode,
71
69
  default: RELATIONSHIP_TARGET_MODE::INTERNAL, as: :targetMode
72
70
 
73
- def external? = targetMode == RELATIONSHIP_TARGET_MODE::EXTERNAL
71
+ def external?
72
+ targetMode == RELATIONSHIP_TARGET_MODE::EXTERNAL
73
+ end
74
74
  end
75
75
 
76
76
  # `<Relationships>`, the root of a `.rels` item.
@@ -92,7 +92,9 @@ module Pptx
92
92
  end
93
93
 
94
94
  # Bytes for a `.rels` item, with the XML declaration.
95
- def xml_file_bytes = Oxml.serialize_part_xml(self)
95
+ def xml_file_bytes
96
+ Oxml.serialize_part_xml(self)
97
+ end
96
98
  end
97
99
  end
98
100
  end
@@ -99,7 +99,9 @@ module Pptx
99
99
 
100
100
  # The part name without its leading slash -- the form used as the Zip
101
101
  # entry name.
102
- def member_name = @to_s[1..]
102
+ def member_name
103
+ @to_s[1..]
104
+ end
103
105
 
104
106
  # A reference to this part relative to +base_uri+, as written into a
105
107
  # .rels part.
@@ -130,14 +132,22 @@ module Pptx
130
132
  @to_s <=> other.to_s
131
133
  end
132
134
 
133
- def ==(other) = (self <=> other)&.zero? || false
135
+ def ==(other)
136
+ (self <=> other)&.zero? || false
137
+ end
134
138
  alias eql? ==
135
139
 
136
- def hash = @to_s.hash
140
+ def hash
141
+ @to_s.hash
142
+ end
137
143
 
138
- def to_str = @to_s
144
+ def to_str
145
+ @to_s
146
+ end
139
147
 
140
- def inspect = "#<Pptx::Opc::PackURI #{@to_s.inspect}>"
148
+ def inspect
149
+ "#<Pptx::Opc::PackURI #{@to_s.inspect}>"
150
+ end
141
151
 
142
152
  PACKAGE = new("/")
143
153
  CONTENT_TYPES = new("/[Content_Types].xml")
@@ -15,7 +15,9 @@ module Pptx
15
15
  #
16
16
  # @raise [NotFoundError] when there is no such relationship
17
17
  # @raise [Error] when there is more than one
18
- def part_related_by(reltype) = rels.part_with_reltype(reltype)
18
+ def part_related_by(reltype)
19
+ rels.part_with_reltype(reltype)
20
+ end
19
21
 
20
22
  # Relate this part to +target+, returning the rId. An existing matching
21
23
  # relationship is reused rather than duplicated.
@@ -29,12 +31,18 @@ module Pptx
29
31
  end
30
32
  end
31
33
 
32
- def related_part(r_id) = rels.fetch(r_id).target_part
34
+ def related_part(r_id)
35
+ rels.fetch(r_id).target_part
36
+ end
33
37
 
34
- def target_ref(r_id) = rels.fetch(r_id).target_ref
38
+ def target_ref(r_id)
39
+ rels.fetch(r_id).target_ref
40
+ end
35
41
 
36
42
  # @return [Relationships]
37
- def rels = raise(NotImplementedError, "#{self.class} must implement #rels")
43
+ def rels
44
+ raise(NotImplementedError, "#{self.class} must implement #rels")
45
+ end
38
46
  end
39
47
 
40
48
  # An OPC package: the object graph behind a .pptx file.
@@ -43,18 +51,26 @@ module Pptx
43
51
 
44
52
  # Open a package from a path, an IO stream, or a directory holding an
45
53
  # unzipped package.
46
- def self.open(pkg_file) = new(pkg_file).load
54
+ def self.open(pkg_file)
55
+ new(pkg_file).load
56
+ end
47
57
 
48
58
  def initialize(pkg_file = nil)
49
59
  @pkg_file = pkg_file
50
60
  end
51
61
 
52
- def rels = @rels ||= Relationships.new(PackURI::PACKAGE.base_uri)
62
+ def rels
63
+ @rels ||= Relationships.new(PackURI::PACKAGE.base_uri)
64
+ end
53
65
 
54
- def drop_rel(r_id) = rels.delete(r_id)
66
+ def drop_rel(r_id)
67
+ rels.delete(r_id)
68
+ end
55
69
 
56
70
  # The presentation part, which is the package's main document part.
57
- def main_document_part = part_related_by(RELATIONSHIP_TYPE::OFFICE_DOCUMENT)
71
+ def main_document_part
72
+ part_related_by(RELATIONSHIP_TYPE::OFFICE_DOCUMENT)
73
+ end
58
74
 
59
75
  # Every part in the package, each yielded once.
60
76
  def parts
@@ -125,7 +141,9 @@ module Pptx
125
141
  # Loads a package from its serialized form.
126
142
  class PackageLoader
127
143
  # @return [Array(Oxml::CT_Relationships, Hash{String=>Part})]
128
- def self.load(pkg_file, package) = new(pkg_file, package).load
144
+ def self.load(pkg_file, package)
145
+ new(pkg_file, package).load
146
+ end
129
147
 
130
148
  def initialize(pkg_file, package)
131
149
  @pkg_file = pkg_file
@@ -140,7 +158,9 @@ module Pptx
140
158
 
141
159
  private
142
160
 
143
- def reader = @reader ||= PackageReader.new(@pkg_file)
161
+ def reader
162
+ @reader ||= PackageReader.new(@pkg_file)
163
+ end
144
164
 
145
165
  def content_types
146
166
  @content_types ||= ContentTypeMap.from_xml(reader[PackURI::CONTENT_TYPES])
@@ -199,7 +219,9 @@ module Pptx
199
219
 
200
220
  attr_reader :partname, :content_type, :package
201
221
 
202
- def self.load(partname, content_type, package, blob) = new(partname, content_type, package, blob)
222
+ def self.load(partname, content_type, package, blob)
223
+ new(partname, content_type, package, blob)
224
+ end
203
225
 
204
226
  def initialize(partname, content_type, package, blob = nil)
205
227
  @partname = partname
@@ -215,19 +237,27 @@ module Pptx
215
237
  end
216
238
 
217
239
  # @return [String] the bytes this part serializes to
218
- def blob = @blob || ""
240
+ def blob
241
+ @blob || ""
242
+ end
219
243
 
220
244
  attr_writer :blob
221
245
 
222
- def rels = @rels ||= Relationships.new(@partname.base_uri)
246
+ def rels
247
+ @rels ||= Relationships.new(@partname.base_uri)
248
+ end
223
249
 
224
250
  def load_rels_from_xml(xml_rels, parts)
225
251
  rels.load_from_xml(@partname.base_uri, xml_rels, parts)
226
252
  end
227
253
 
228
- def drop_rel(r_id) = rels.delete(r_id)
254
+ def drop_rel(r_id)
255
+ rels.delete(r_id)
256
+ end
229
257
 
230
- def inspect = "#<#{self.class.name} #{@partname}>"
258
+ def inspect
259
+ "#<#{self.class.name} #{@partname}>"
260
+ end
231
261
  end
232
262
 
233
263
  # A part whose payload is XML, which is most of them.
@@ -243,11 +273,15 @@ module Pptx
243
273
  @element = element
244
274
  end
245
275
 
246
- def blob = Oxml.serialize_part_xml(@element)
276
+ def blob
277
+ Oxml.serialize_part_xml(@element)
278
+ end
247
279
 
248
280
  # This part. Objects further down the tree delegate up to find the part
249
281
  # they live in; the chain ends here.
250
- def part = self
282
+ def part
283
+ self
284
+ end
251
285
 
252
286
  # Drop a relationship unless the XML still refers to it more than once.
253
287
  #
@@ -274,12 +308,18 @@ module Pptx
274
308
  @part_type_for[content_type] = part_class
275
309
  end
276
310
 
277
- def part_class_for(content_type) = @part_type_for.fetch(content_type, Part)
311
+ def part_class_for(content_type)
312
+ @part_type_for.fetch(content_type, Part)
313
+ end
278
314
 
279
- def registered = @part_type_for.dup
315
+ def registered
316
+ @part_type_for.dup
317
+ end
280
318
 
281
319
  # Test seam: restore a previous registration table.
282
- def reset!(to) = (@part_type_for = to)
320
+ def reset!(to)
321
+ (@part_type_for = to)
322
+ end
283
323
 
284
324
  def build(partname, content_type, package, blob)
285
325
  part_class_for(content_type).load(partname, content_type, package, blob)
@@ -325,21 +365,41 @@ module Pptx
325
365
  @rels = {}
326
366
  end
327
367
 
328
- def each(&) = @rels.each_value(&)
368
+ def each(&)
369
+ @rels.each_value(&)
370
+ end
329
371
 
330
- def each_value(&) = @rels.each_value(&)
372
+ def each_value(&)
373
+ @rels.each_value(&)
374
+ end
331
375
 
332
- def [](r_id) = @rels[r_id]
376
+ def [](r_id)
377
+ @rels[r_id]
378
+ end
333
379
 
334
380
  def fetch(r_id)
335
381
  @rels.fetch(r_id) { raise NotFoundError, "no relationship with key #{r_id.inspect}" }
336
382
  end
337
383
 
338
- def key?(r_id) = @rels.key?(r_id)
339
- def keys = @rels.keys
340
- def size = @rels.size
341
- def empty? = @rels.empty?
342
- def delete(r_id) = @rels.delete(r_id)
384
+ def key?(r_id)
385
+ @rels.key?(r_id)
386
+ end
387
+
388
+ def keys
389
+ @rels.keys
390
+ end
391
+
392
+ def size
393
+ @rels.size
394
+ end
395
+
396
+ def empty?
397
+ @rels.empty?
398
+ end
399
+
400
+ def delete(r_id)
401
+ @rels.delete(r_id)
402
+ end
343
403
 
344
404
  # The rId of a relationship of +reltype+ to +target_part+, adding one if
345
405
  # no match exists.
@@ -458,7 +518,9 @@ module Pptx
458
518
  end
459
519
 
460
520
  # True when the target is outside the package, such as a URL.
461
- def external? = @target_mode == RELATIONSHIP_TARGET_MODE::EXTERNAL
521
+ def external?
522
+ @target_mode == RELATIONSHIP_TARGET_MODE::EXTERNAL
523
+ end
462
524
 
463
525
  def target_part
464
526
  raise Error, "#target_part is undefined for an external relationship" if external?
@@ -474,9 +536,13 @@ module Pptx
474
536
 
475
537
  # The reference as written into the `.rels` item: a relative partname
476
538
  # internally, or the URL for an external relationship.
477
- def target_ref = external? ? @target : target_partname.relative_ref(@base_uri)
539
+ def target_ref
540
+ external? ? @target : target_partname.relative_ref(@base_uri)
541
+ end
478
542
 
479
- def inspect = "#<Pptx::Opc::Relationship #{@r_id} #{@reltype}>"
543
+ def inspect
544
+ "#<Pptx::Opc::Relationship #{@r_id} #{@reltype}>"
545
+ end
480
546
  end
481
547
  end
482
548
  end
@@ -20,11 +20,15 @@ module Pptx
20
20
  end
21
21
 
22
22
  # @return [Boolean] whether the package holds an item at +pack_uri+
23
- def key?(pack_uri) = @reader.key?(pack_uri)
23
+ def key?(pack_uri)
24
+ @reader.key?(pack_uri)
25
+ end
24
26
 
25
27
  # @return [String] binary contents of the item at +pack_uri+
26
28
  # @raise [KeyError] when there is no such item
27
- def [](pack_uri) = @reader[pack_uri]
29
+ def [](pack_uri)
30
+ @reader[pack_uri]
31
+ end
28
32
 
29
33
  # The XML of the `.rels` item belonging to +partname+, or nil when that
30
34
  # part has no relationships.
@@ -86,7 +90,9 @@ module Pptx
86
90
  @path = File.expand_path(path)
87
91
  end
88
92
 
89
- def key?(pack_uri) = File.file?(path_for(pack_uri))
93
+ def key?(pack_uri)
94
+ File.file?(path_for(pack_uri))
95
+ end
90
96
 
91
97
  def [](pack_uri)
92
98
  File.binread(path_for(pack_uri))
@@ -115,7 +121,9 @@ module Pptx
115
121
  @pkg_file = pkg_file
116
122
  end
117
123
 
118
- def key?(pack_uri) = blobs.key?(pack_uri.to_s)
124
+ def key?(pack_uri)
125
+ blobs.key?(pack_uri.to_s)
126
+ end
119
127
 
120
128
  def [](pack_uri)
121
129
  blobs.fetch(pack_uri.to_s) { raise KeyError, "no member #{pack_uri} in package" }
@@ -132,9 +140,11 @@ module Pptx
132
140
  def each_entry(&block)
133
141
  return enum_for(:each_entry) unless block
134
142
 
143
+ # get_input_stream without a block opens a file handle per member and
144
+ # leaves it for GC; on Windows that keeps the .pptx locked after open.
135
145
  open_zip do |zip|
136
146
  zip.each do |entry|
137
- block.call(entry.name, entry.get_input_stream.read) if entry.file?
147
+ block.call(entry.name, entry.get_input_stream(&:read)) if entry.file?
138
148
  end
139
149
  end
140
150
  end