Class: Gem::SpecificationPolicy

Inherits:
Object
  • Object
show all
Includes:
UserInteraction
Defined in:
lib/rubygems/specification_policy.rb

Constant Summary collapse

VALID_NAME_PATTERN =

:nodoc:

/\A[a-zA-Z0-9\.\-\_]+\z/
SPECIAL_CHARACTERS =

:nodoc:

/\A[#{Regexp.escape(".-_")}]+/
VALID_URI_PATTERN =

:nodoc:

%r{\Ahttps?:\/\/([^\s:@]+:[^\s:@]*@)?[A-Za-z\d\-]+(\.[A-Za-z\d\-]+)+\.?(:\d{1,5})?([\/?]\S*)?\z}
%w[
  homepage_uri
  changelog_uri
  source_code_uri
  documentation_uri
  wiki_uri
  mailing_list_uri
  bug_tracker_uri
  download_uri
  funding_uri
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from UserInteraction

#alert, #alert_error, #alert_warning, #ask, #ask_for_password, #ask_yes_no, #choose_from_list, #say, #terminate_interaction, #verbose

Methods included from DefaultUserInteraction

ui, #ui, ui=, #ui=, use_ui, #use_ui

Methods included from Text

#clean_text, #format_text, #levenshtein_distance, #min3, #truncate_text

Constructor Details

#initialize(specification) ⇒ SpecificationPolicy

:nodoc:



26
27
28
29
30
# File 'lib/rubygems/specification_policy.rb', line 26

def initialize(specification)
  @warnings = 0

  @specification = specification
end

Instance Attribute Details

#packagingObject

If set to true, run packaging-specific checks, as well.



35
36
37
# File 'lib/rubygems/specification_policy.rb', line 35

def packaging
  @packaging
end

Instance Method Details

#validate(strict = false) ⇒ Object

Does a sanity check on the specification.

Raises InvalidSpecificationException if the spec does not pass the checks.

It also performs some validations that do not raise but print warning messages instead.



46
47
48
49
50
51
52
53
# File 'lib/rubygems/specification_policy.rb', line 46

def validate(strict = false)
  validate_required!
  validate_required_metadata!

  validate_optional(strict) if packaging || strict

  true
end

#validate_dependenciesObject

Checks that the gem does not depend on itself. Checks that dependencies use requirements as we recommend. Warnings are issued when dependencies are open-ended or overly strict for semantic versioning.



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/rubygems/specification_policy.rb', line 197

def validate_dependencies # :nodoc:
  warning_messages = []
  @specification.dependencies.each do |dep|
    if dep.name == @specification.name # warn on self reference
      warning_messages << "Self referencing dependency is unnecessary and strongly discouraged."
    end

    prerelease_dep = dep.requirements_list.any? do |req|
      Gem::Requirement.new(req).prerelease?
    end

    warning_messages << "prerelease dependency on #{dep} is not recommended" if
        prerelease_dep && !@specification.version.prerelease?

    open_ended = dep.requirement.requirements.all? do |op, version|
      !version.prerelease? && [">", ">="].include?(op)
    end

    next unless open_ended
    op, dep_version = dep.requirement.requirements.first

    segments = dep_version.segments

    base = segments.first 2

    recommendation = if [">", ">="].include?(op) && segments == [0]
      "  use a bounded requirement, such as \"~> x.y\""
    else
      bugfix = if op == ">"
        ", \"> #{dep_version}\""
      elsif op == ">=" && base != segments
        ", \">= #{dep_version}\""
      end

      "  if #{dep.name} is semantically versioned, use:\n" \
      "    add_#{dep.type}_dependency \"#{dep.name}\", \"~> #{base.join "."}\"#{bugfix}"
    end

    warning_messages << ["open-ended dependency on #{dep} is not recommended", recommendation].join("\n") + "\n"
  end
  if warning_messages.any?
    warning_messages.each {|warning_message| warning warning_message }
  end
end

#validate_duplicate_dependenciesObject

Checks that no duplicate dependencies are specified.



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/rubygems/specification_policy.rb', line 171

def validate_duplicate_dependencies # :nodoc:
  # NOTE: see REFACTOR note in Gem::Dependency about types - this might be brittle
  seen = Gem::Dependency::TYPES.inject({}) {|types, type| types.merge({ type => {} }) }

  error_messages = []
  @specification.dependencies.each do |dep|
    if prev = seen[dep.type][dep.name]
      error_messages << <<-MESSAGE
duplicate dependency on #{dep}, (#{prev.requirement}) use:
  add_#{dep.type}_dependency \"#{dep.name}\", \"#{dep.requirement}\", \"#{prev.requirement}\"
      MESSAGE
    end

    seen[dep.type][dep.name] = dep
  end
  if error_messages.any?
    error error_messages.join
  end
end

#validate_for_resolutionObject

Implementation for Specification#validate_for_resolution



129
130
131
# File 'lib/rubygems/specification_policy.rb', line 129

def validate_for_resolution
  validate_required!
end

#validate_metadataObject

Implementation for Specification#validate_metadata



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/rubygems/specification_policy.rb', line 136

def 
   = @specification.

  unless Hash === 
    error "metadata must be a hash"
  end

  .each do |key, value|
    entry = "metadata['#{key}']"
    unless key.is_a?(String)
      error "metadata keys must be a String"
    end

    if key.size > 128
      error "metadata key is too large (#{key.size} > 128)"
    end

    unless value.is_a?(String)
      error "#{entry} value must be a String"
    end

    if value.size > 1024
      error "#{entry} value is too large (#{value.size} > 1024)"
    end

    next unless METADATA_LINK_KEYS.include? key
    unless VALID_URI_PATTERN.match?(value)
      error "#{entry} has invalid link: #{value.inspect}"
    end
  end
end

#validate_optional(strict) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/rubygems/specification_policy.rb', line 100

def validate_optional(strict)
  validate_licenses

  validate_permissions

  validate_values

  validate_dependencies

  validate_required_ruby_version

  validate_extensions

  validate_removed_attributes

  validate_unique_links

  if @warnings > 0
    if strict
      error "specification has warnings"
    else
      alert_warning help_text
    end
  end
end

#validate_permissionsObject

Issues a warning for each file to be packaged which is world-readable.

Implementation for Specification#validate_permissions



253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/rubygems/specification_policy.rb', line 253

def validate_permissions
  return if Gem.win_platform?

  @specification.files.each do |file|
    next unless File.file?(file)
    next if File.stat(file).mode & 0o444 == 0o444
    warning "#{file} is not world-readable"
  end

  @specification.executables.each do |name|
    exec = File.join @specification.bindir, name
    next unless File.file?(exec)
    next if File.stat(exec).executable?
    warning "#{exec} is not executable"
  end
end

#validate_required!Object

Does a sanity check on the specification.

Raises InvalidSpecificationException if the spec does not pass the checks.

Only runs checks that are considered necessary for the specification to be functional.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/rubygems/specification_policy.rb', line 64

def validate_required!
  validate_nil_attributes

  validate_rubygems_version

  validate_required_attributes

  validate_name

  validate_require_paths

  @specification.keep_only_files_and_directories

  validate_non_files

  validate_self_inclusion_in_files_list

  validate_specification_version

  validate_platform

  validate_array_attributes

  validate_authors_field

  validate_licenses_length

  validate_duplicate_dependencies
end

#validate_required_metadata!Object



94
95
96
97
98
# File 'lib/rubygems/specification_policy.rb', line 94

def validate_required_metadata!
  

  
end

#validate_required_ruby_versionObject



242
243
244
245
246
# File 'lib/rubygems/specification_policy.rb', line 242

def validate_required_ruby_version
  if @specification.required_ruby_version.requirements == [Gem::Requirement::DefaultRequirement]
    warning "make sure you specify the oldest ruby version constraint (like \">= 3.0\") that you want your gem to support by setting the `required_ruby_version` gemspec attribute"
  end
end