pixar-ruby-extensions 1.11.1

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 (34) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +177 -0
  3. data/README.md +29 -0
  4. data/lib/pixar-ruby-extensions.rb +10 -0
  5. data/lib/pixar_ruby_extensions/array/predicates.rb +30 -0
  6. data/lib/pixar_ruby_extensions/array/utils.rb +88 -0
  7. data/lib/pixar_ruby_extensions/array.rb +17 -0
  8. data/lib/pixar_ruby_extensions/filetest/predicates.rb +38 -0
  9. data/lib/pixar_ruby_extensions/filetest.rb +14 -0
  10. data/lib/pixar_ruby_extensions/float/utils.rb +36 -0
  11. data/lib/pixar_ruby_extensions/float.rb +14 -0
  12. data/lib/pixar_ruby_extensions/hash/utils.rb +94 -0
  13. data/lib/pixar_ruby_extensions/hash.rb +15 -0
  14. data/lib/pixar_ruby_extensions/integer/utils.rb +187 -0
  15. data/lib/pixar_ruby_extensions/integer.rb +14 -0
  16. data/lib/pixar_ruby_extensions/ipaddr/predicates.rb +50 -0
  17. data/lib/pixar_ruby_extensions/ipaddr/utils.rb +77 -0
  18. data/lib/pixar_ruby_extensions/ipaddr.rb +20 -0
  19. data/lib/pixar_ruby_extensions/json/jsonl.rb +50 -0
  20. data/lib/pixar_ruby_extensions/json/utils.rb +78 -0
  21. data/lib/pixar_ruby_extensions/json.rb +17 -0
  22. data/lib/pixar_ruby_extensions/object/predicates.rb +49 -0
  23. data/lib/pixar_ruby_extensions/object.rb +15 -0
  24. data/lib/pixar_ruby_extensions/pathname/predicates.rb +38 -0
  25. data/lib/pixar_ruby_extensions/pathname/utils.rb +139 -0
  26. data/lib/pixar_ruby_extensions/pathname.rb +18 -0
  27. data/lib/pixar_ruby_extensions/string/conversions.rb +113 -0
  28. data/lib/pixar_ruby_extensions/string/predicates.rb +52 -0
  29. data/lib/pixar_ruby_extensions/string.rb +17 -0
  30. data/lib/pixar_ruby_extensions/time/utils.rb +46 -0
  31. data/lib/pixar_ruby_extensions/time.rb +16 -0
  32. data/lib/pixar_ruby_extensions/version.rb +15 -0
  33. data/lib/pixar_ruby_extensions.rb +44 -0
  34. metadata +78 -0
@@ -0,0 +1,139 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ module PixarRubyExtensions
9
+
10
+ module PathnameExtensions
11
+
12
+ module Utils
13
+
14
+ require 'fileutils'
15
+
16
+ # Copy a path to a destination
17
+ # @see FileUtils.cp
18
+ def pix_cp(dest, **options)
19
+ FileUtils.cp @path, dest.to_s, **options
20
+ end # cp
21
+
22
+ # Recursively copy this path to a destination
23
+ # @see FileUtils.cp_r
24
+ def pix_cp_r(dest, **options)
25
+ FileUtils.cp_r @path, dest.to_s, **options
26
+ end # cp
27
+
28
+ # Write some string content to a file.
29
+ #
30
+ # Simpler than always using an open('w') block
31
+ #
32
+ # *CAUTION* this overwrites files!
33
+ #
34
+ def pix_save(content)
35
+ self.open('w') { |f| f.write content.to_s }
36
+ end
37
+
38
+ # Append some string content to a file.
39
+ #
40
+ # Simpler than always using an open('a') block
41
+ #
42
+ def pix_append(content)
43
+ self.open('a') { |f| f.write content.to_s }
44
+ end
45
+
46
+ # Not sure why this isn't in Pathname to begin with
47
+ #
48
+ # @see FileUtils.touch
49
+ def pix_touch
50
+ FileUtils.touch @path
51
+ end
52
+
53
+ # Pathname should use FileUtils.chown, not File.chown, its friendlier
54
+ def pix_chown(usr, grp)
55
+ FileUtils.chown usr, grp, @path
56
+ end
57
+
58
+ # Pathnames often need to be escaped for the shell
59
+ def pix_shellescape
60
+ require 'shellwords'
61
+ to_s.shellescape
62
+ end
63
+
64
+ # This allows us to write out to a file which many other
65
+ # threads or processes are reading, and not worry about
66
+ # them reading a partial file.
67
+ # It does so by writing into a temp file in the same directory,
68
+ # then renaming the file into the path `self`
69
+ #
70
+ # NOTE: There is much discussion online about the atomicity of
71
+ # unix 'rename' but in general as long as you're dealing with
72
+ # a single file, not a directory, and you are not moving it across
73
+ # filesystems, then yes, it will be atomic.
74
+ #
75
+ # WARNING: This will overwrite the current file.
76
+ #
77
+ # @param data [String] the data to write into the file.
78
+ #
79
+ # @return [void]
80
+ #
81
+ def pix_atomic_write(data)
82
+ raise "#{self} is a directory" if directory?
83
+
84
+ require 'tempfile'
85
+ tmpf = Pathname.new Tempfile.create(
86
+ ['.atomic_write', '.tmp'],
87
+ parent.to_s
88
+ )
89
+
90
+ if file?
91
+ ostat = stat
92
+ mode = ostat.mode
93
+ uid = ostat.uid
94
+ gid = ostat.gid
95
+ else
96
+ mode = 0o644
97
+ uid = nil
98
+ gid = nil
99
+ end
100
+
101
+ tmpf.chmod mode
102
+ tmpf.pix_chown(uid, gid) if uid && gid
103
+
104
+ tmpf.open('w+') { |f| f.write data }
105
+ tmpf.rename self
106
+ ensure
107
+ tmpf.delete if tmpf && tmpf.file?
108
+ end # end atomic_write
109
+
110
+ # DEPRECATED: use the pix_ version of this method
111
+ alias atomic_write pix_atomic_write
112
+
113
+ # @see PixarRubyExtensions::IntegerExtensions::Utils#pix_humanize_bytes
114
+ #
115
+ # @return [String] The human-readable file size.
116
+ #
117
+ def pix_humanize_size
118
+ # make sure we require this, in case the user only required
119
+ # 'pixar_ruby_extensions/pathname'
120
+ require 'pixar_ruby_extensions/integer'
121
+ size.pix_humanize_bytes
122
+ end
123
+
124
+ # The same as #pix_humanize_size except returns nil if
125
+ # the file size is zero, or the file doesn't exist.
126
+ #
127
+ # @return [String, nil] The human-readable file size, or nil
128
+ def pix_humanize_size?(show_unit: false)
129
+ return unless exist?
130
+ return if size.zero?
131
+
132
+ humanize_size
133
+ end
134
+
135
+ end # module
136
+
137
+ end # module
138
+
139
+ end # module
@@ -0,0 +1,18 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ require 'pathname'
9
+ require 'pixar_ruby_extensions/pathname/utils'
10
+ require 'pixar_ruby_extensions/pathname/predicates'
11
+
12
+ # include the modules loaded above
13
+ class Pathname
14
+
15
+ include PixarRubyExtensions::PathnameExtensions::Predicates
16
+ include PixarRubyExtensions::PathnameExtensions::Utils
17
+
18
+ end
@@ -0,0 +1,113 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ module PixarRubyExtensions
9
+
10
+ module StringExtensions
11
+
12
+ module Conversions
13
+
14
+ TRUE_STR = 'true'
15
+ FALSE_STR = 'false'
16
+
17
+ # Convert the strings "true" and "false"
18
+ # (after stripping whitespace and downcasing)
19
+ # to true and false respectively
20
+ #
21
+ # Return nil if any other string.
22
+ #
23
+ # @return [Boolean,nil] the boolean value. Nil if n/a
24
+ #
25
+ def pix_to_bool
26
+ case strip.downcase
27
+ when TRUE_STR then true
28
+ when FALSE_STR then false
29
+ end # case
30
+ end # to bool
31
+
32
+ # Convert a string to a Time object using Time.parse
33
+ #
34
+ # @return [Time] the time represented by the string, or nil
35
+ #
36
+ def pix_to_time
37
+ # needed to get .parse
38
+ require 'time'
39
+
40
+ ::Time.parse self
41
+ rescue
42
+ nil
43
+ end
44
+
45
+ # Convert a String to a Pathname object
46
+ #
47
+ # @return [Pathname]
48
+ #
49
+ def pix_to_pathname
50
+ ::Pathname.new self
51
+ end
52
+ alias pix_to_path pix_to_pathname
53
+
54
+ # Word-wrap a string to a max width.
55
+ # By default, runs of newlines are preserved.
56
+ #
57
+ # Regexp found at http://www.java2s.com/Code/Ruby/String/WordwrappingLinesofText.htm
58
+ #
59
+ # @param width [Integer] Must be a positive Integer. Defaults to 2 columns less than
60
+ # the current terminal width, or 78 if terminal width cannot be obtained.
61
+ #
62
+ # @param preserve_newlines [Boolean] Should runs of 2+ newlines be preserved?
63
+ # Defaults to true. If false, runs of newlines become a single newline.
64
+ #
65
+ # @return [String] The string word-wrapped to lines no more than <width> chars long.
66
+ #
67
+ def pix_word_wrap(width = nil, preserve_newlines: true)
68
+ if width.nil?
69
+ begin
70
+ require 'io/console'
71
+ width = IO.console.winsize.last - 2
72
+ rescue
73
+ width = 78
74
+ end
75
+ else
76
+ width = width.to_i
77
+ raise ArgumentError, 'Width must be an iteger > 0' unless width.positive?
78
+ end
79
+
80
+ return lines.map { |l| l.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n") }.join if preserve_newlines
81
+
82
+ gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n")
83
+ end
84
+
85
+ # Encode this string to be used when building a URL.
86
+ #
87
+ # DO NOT use this to encode an entire URL, or any part of a URL that has
88
+ # characters that shouldn't be encoded - as it will encode the slashes and other
89
+ # proper URL parts, e.g.
90
+ #
91
+ # url = 'http://foobar.com/foo?bar=this has spaces'.pix_url_encode
92
+ # # => "http%3A%2F%2Ffoobar.com%2Ffoo%3Fbar%3Dthis%20has%20spaces"
93
+ #
94
+ # Instead just convert any appropriate sub-part of the URL
95
+ #
96
+ # endoded_value = 'this has spaces'.pix_url_encode
97
+ # url = "http://foobar.com/foo?bar=#{endoded_value}"
98
+ # # => "http://foobar.com/foo?bar=this%20has%20spaces"
99
+ #
100
+ # This uses ERB::Util.url_encode, which converts spaces to '%20'.
101
+ # Consult the interwebs for the differences between '%20' and '+', and
102
+ # ERB::Util.url_encode vs CGI.escape
103
+ #
104
+ def pix_url_encode
105
+ require 'erb'
106
+ ERB::Util.url_encode self
107
+ end
108
+
109
+ end # module
110
+
111
+ end # module
112
+
113
+ end # module
@@ -0,0 +1,52 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ module PixarRubyExtensions
9
+
10
+ module StringExtensions
11
+
12
+ module Predicates
13
+
14
+ INTEGER_RE = /\A-?[0-9]+\Z/.freeze
15
+ FLOAT_RE = /\A-?[0-9]+\.[0-9]+\Z/.freeze
16
+
17
+ # Does this string contain an integer?
18
+ # (i.e. it consists only of numeric digits,
19
+ # maybe with a dash in front)
20
+ #
21
+ # @return [Boolean]
22
+ #
23
+ def pix_integer?
24
+ self =~ INTEGER_RE ? true : false
25
+ end
26
+
27
+ # Does this string contain a float?
28
+ # (i.e. it consists only of numeric digits,
29
+ # maybe with a dash in front followed by one
30
+ # dot, followed by at least one more digit)
31
+ #
32
+ # @return [Boolean]
33
+ #
34
+ def pix_float?
35
+ self =~ FLOAT_RE ? true : false
36
+ end
37
+
38
+ # is this some representation of a number?
39
+ #
40
+ # @return [Boolean]
41
+ #
42
+ def pix_numeric?
43
+ true if Float(self)
44
+ rescue
45
+ false
46
+ end
47
+
48
+ end # module
49
+
50
+ end # module
51
+
52
+ end # module
@@ -0,0 +1,17 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ require 'pixar_ruby_extensions/string/conversions'
9
+ require 'pixar_ruby_extensions/string/predicates'
10
+
11
+ # include the modules loaded above
12
+ class String
13
+
14
+ include PixarRubyExtensions::StringExtensions::Predicates
15
+ include PixarRubyExtensions::StringExtensions::Conversions
16
+
17
+ end
@@ -0,0 +1,46 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ module PixarRubyExtensions
9
+
10
+ module TimeExtensions
11
+
12
+ module Utils
13
+
14
+ # @return [Integer] the milliseconds of the Time
15
+ def pix_msec
16
+ strftime('%L').to_i
17
+ end
18
+
19
+ # This is useful for anyone who interacts with the Jamf Pro APIs, which
20
+ # often deliver timestamps as the unix epoch in milliseconds.
21
+ # e.g. '2023-02-28 14:43:41.456 -0800' would be 1677624221456
22
+ #
23
+ # @return [Integer] The Time as a unix epoch with milliseconds appended
24
+ def pix_to_epoch_with_msecs
25
+ msec = strftime('%L').rjust(3, '0')
26
+ epoch = strftime('%s')
27
+ "#{epoch}#{msec}".to_i
28
+ end
29
+
30
+ # @return [String] the Time formatted for our logs and UI display.
31
+ # '%F %T' is short for '%Y-%m-%d %H:%M:%S'
32
+ def pix_to_display
33
+ strftime '%F %T'
34
+ end
35
+
36
+ # @return [String] the Time formatted as iso8601 with the
37
+ # milliseconds
38
+ def pix_to_iso8601_with_msecs
39
+ strftime("%FT%T.#{pix_msec}%z")
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,16 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ require 'time'
9
+ require 'pixar_ruby_extensions/time/utils'
10
+
11
+ # include the modules loaded above
12
+ class Time
13
+
14
+ include PixarRubyExtensions::TimeExtensions::Utils
15
+
16
+ end
@@ -0,0 +1,15 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+ #
6
+ #
7
+
8
+ # frozen_string_literal: true
9
+
10
+ # our version
11
+ module PixarRubyExtensions
12
+
13
+ VERSION = '1.11.1'
14
+
15
+ end
@@ -0,0 +1,44 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+ #
6
+ #
7
+
8
+ # frozen_string_literal: true
9
+
10
+ # These are extensions to Ruby modules and classes in Ruby's Core
11
+ # and Standard Library. We've put them here because we've found
12
+ # ourselves performing these tasks repeatedly in our code over the years
13
+ # and we like to stay DRY.
14
+ # They are also used in our open-source projects, and their use there
15
+ # will be migrating to use this gem, rather than their built-in
16
+ # versions - also in pursuit of DRYness.
17
+
18
+ # To ease troubleshooting and prevent name collisions:
19
+
20
+ # - With only a couple of exceptions, all monkey-patched methods are
21
+ # prefixed with "pix_"
22
+
23
+ # - Methods are not directly monkey-patched into the Core or StdLib classes/modules.
24
+ # Instead they are defined in modules with obvious namespaces, and mixed-in to the
25
+ # Core or StdLib classes/modules. This provides _much_ easier debugging when there
26
+ # are exceptions, since the error and backtrace will indicate exactly where these
27
+ # methods are defined.
28
+ module PixarRubyExtensions; end
29
+
30
+ require 'pixar_ruby_extensions/version'
31
+
32
+ # NOTE: You may require these individually if you don't need them all.
33
+
34
+ require 'pixar_ruby_extensions/array'
35
+ require 'pixar_ruby_extensions/filetest'
36
+ require 'pixar_ruby_extensions/hash'
37
+ require 'pixar_ruby_extensions/integer'
38
+ require 'pixar_ruby_extensions/float'
39
+ require 'pixar_ruby_extensions/ipaddr'
40
+ require 'pixar_ruby_extensions/json'
41
+ require 'pixar_ruby_extensions/object'
42
+ require 'pixar_ruby_extensions/pathname'
43
+ require 'pixar_ruby_extensions/string'
44
+ require 'pixar_ruby_extensions/time'
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pixar-ruby-extensions
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.11.1
5
+ platform: ruby
6
+ authors:
7
+ - Chris Lasell
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-09-28 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |
14
+ This gem contans extensions to the Ruby core and standard libraries which have been used in many
15
+ Pixar projects over the years.
16
+ email: chrisl@pixar.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files:
20
+ - README.md
21
+ - LICENSE.txt
22
+ files:
23
+ - LICENSE.txt
24
+ - README.md
25
+ - lib/pixar-ruby-extensions.rb
26
+ - lib/pixar_ruby_extensions.rb
27
+ - lib/pixar_ruby_extensions/array.rb
28
+ - lib/pixar_ruby_extensions/array/predicates.rb
29
+ - lib/pixar_ruby_extensions/array/utils.rb
30
+ - lib/pixar_ruby_extensions/filetest.rb
31
+ - lib/pixar_ruby_extensions/filetest/predicates.rb
32
+ - lib/pixar_ruby_extensions/float.rb
33
+ - lib/pixar_ruby_extensions/float/utils.rb
34
+ - lib/pixar_ruby_extensions/hash.rb
35
+ - lib/pixar_ruby_extensions/hash/utils.rb
36
+ - lib/pixar_ruby_extensions/integer.rb
37
+ - lib/pixar_ruby_extensions/integer/utils.rb
38
+ - lib/pixar_ruby_extensions/ipaddr.rb
39
+ - lib/pixar_ruby_extensions/ipaddr/predicates.rb
40
+ - lib/pixar_ruby_extensions/ipaddr/utils.rb
41
+ - lib/pixar_ruby_extensions/json.rb
42
+ - lib/pixar_ruby_extensions/json/jsonl.rb
43
+ - lib/pixar_ruby_extensions/json/utils.rb
44
+ - lib/pixar_ruby_extensions/object.rb
45
+ - lib/pixar_ruby_extensions/object/predicates.rb
46
+ - lib/pixar_ruby_extensions/pathname.rb
47
+ - lib/pixar_ruby_extensions/pathname/predicates.rb
48
+ - lib/pixar_ruby_extensions/pathname/utils.rb
49
+ - lib/pixar_ruby_extensions/string.rb
50
+ - lib/pixar_ruby_extensions/string/conversions.rb
51
+ - lib/pixar_ruby_extensions/string/predicates.rb
52
+ - lib/pixar_ruby_extensions/time.rb
53
+ - lib/pixar_ruby_extensions/time/utils.rb
54
+ - lib/pixar_ruby_extensions/version.rb
55
+ homepage: https://github.com/PixarAnimationStudios/pixar-ruby-extensions
56
+ licenses:
57
+ - LicenseRef-LICENSE.txt
58
+ metadata: {}
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 2.6.3
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubygems_version: 3.3.11
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: Extensions to Ruby Core and Ctandard libraries used in Pixar's ruby projects
78
+ test_files: []