pax_global_header00006660000000000000000000000064146663447430014533gustar00rootroot0000000000000052 comment=a4be216146cc1d08ca415fed86171f1cdf440628 puppetlabs-puppet-strings-a4be216/000077500000000000000000000000001466634474300173225ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/.fixtures.yml000066400000000000000000000004611466634474300217750ustar00rootroot00000000000000fixtures: repositories: facts: 'https://github.com/puppetlabs/puppetlabs-facts.git' provision: 'https://github.com/puppetlabs/provision.git' puppet_agent: 'https://github.com/puppetlabs/puppetlabs-puppet_agent.git' symlinks: test: "#{source_dir}/spec/fixtures/acceptance/modules/test" puppetlabs-puppet-strings-a4be216/.github/000077500000000000000000000000001466634474300206625ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/.github/pull_request_template.md000066400000000000000000000006701466634474300256260ustar00rootroot00000000000000## Summary Provide a detailed description of all the changes present in this pull request. ## Additional Context Add any additional context about the problem here. - [ ] Root cause and the steps to reproduce. (If applicable) - [ ] Thought process behind the implementation. ## Related Issues (if any) Mention any related issues or pull requests. ## Checklist - [ ] 🟢 Spec tests. - [ ] 🟢 Acceptance tests. - [ ] Manually verified. puppetlabs-puppet-strings-a4be216/.github/workflows/000077500000000000000000000000001466634474300227175ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/.github/workflows/ci.yml000066400000000000000000000030571466634474300240420ustar00rootroot00000000000000name: "ci" on: push: branches: - "main" pull_request: branches: - "main" workflow_dispatch: env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} jobs: spec: strategy: fail-fast: false matrix: ruby_version: - "2.7" - "3.2" include: - ruby-version: '2.7' puppet_gem_version: '~> 7.0' - ruby_version: '3.2' puppet_gem_version: '~> 8.0' runs_on: - "ubuntu-latest" - "windows-latest" name: "spec (${{ matrix.runs_on }} ruby ${{ matrix.ruby_version }} | puppet ${{matrix.puppet_gem_version}})" uses: "puppetlabs/cat-github-actions/.github/workflows/gem_ci.yml@main" secrets: "inherit" with: rake_task: "spec:coverage" ruby_version: ${{ matrix.ruby_version }} puppet_gem_version: ${{ matrix.puppet_gem_version }} runs_on: ${{ matrix.runs_on }} acceptance: needs: "spec" strategy: matrix: ruby_version: - "2.7" - "3.2" include: - ruby-version: '2.7' puppet_gem_version: '~> 7.0' - ruby_version: '3.2' puppet_gem_version: 'https://github.com/puppetlabs/puppet' # puppet8' runs_on: - "ubuntu-latest" - "windows-latest" uses: "puppetlabs/cat-github-actions/.github/workflows/gem_acceptance.yml@main" secrets: "inherit" with: ruby_version: ${{ matrix.ruby_version }} puppet_version: ${{ matrix.puppet_gem_version }} runs_on: ${{ matrix.runs_on }} puppetlabs-puppet-strings-a4be216/.github/workflows/jekyll-gh-pages.yml000066400000000000000000000024201466634474300264230ustar00rootroot00000000000000name: Deploy GitHub Pages on: # Runs on pushes targeting the default branch push: branches: ["main"] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. concurrency: group: "pages" cancel-in-progress: false jobs: # Build job build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Pages uses: actions/configure-pages@v5 - name: Build with Jekyll uses: actions/jekyll-build-pages@v1 with: source: ./ destination: ./_site - name: Upload artifact uses: actions/upload-pages-artifact@v3 # Deployment job deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 puppetlabs-puppet-strings-a4be216/.github/workflows/mend.yml000066400000000000000000000003661466634474300243720ustar00rootroot00000000000000name: "mend" on: pull_request: branches: - "main" schedule: - cron: "0 0 * * *" workflow_dispatch: jobs: mend: uses: "puppetlabs/cat-github-actions/.github/workflows/tooling_mend_ruby.yml@main" secrets: "inherit" puppetlabs-puppet-strings-a4be216/.github/workflows/nightly.yml000066400000000000000000000026611466634474300251250ustar00rootroot00000000000000name: "nightly" on: schedule: - cron: "0 0 * * *" workflow_dispatch: jobs: spec: strategy: fail-fast: false matrix: ruby_version: - "2.7" - "3.2" include: - ruby-version: '2.7' puppet_gem_version: '~> 7.0' - ruby_version: '3.2' puppet_gem_version: '~> 8.0' runs_on: - "ubuntu-latest" - "windows-latest" name: "spec (${{ matrix.runs_on }} ruby ${{ matrix.ruby_version }} | puppet ${{matrix.puppet_gem_version}})" uses: "puppetlabs/cat-github-actions/.github/workflows/gem_ci.yml@main" secrets: "inherit" with: ruby_version: ${{ matrix.ruby_version }} puppet_gem_version: ${{ matrix.puppet_gem_version }} runs_on: ${{ matrix.runs_on }} acceptance: needs: "spec" strategy: matrix: ruby_version: - "2.7" - "3.2" include: - ruby-version: '2.7' puppet_gem_version: '~> 7.0' - ruby_version: '3.2' puppet_gem_version: 'https://github.com/puppetlabs/puppet' # puppet8' runs_on: - "ubuntu-latest" - "windows-latest" uses: "puppetlabs/cat-github-actions/.github/workflows/gem_acceptance.yml@main" secrets: "inherit" with: ruby_version: ${{ matrix.ruby_version }} puppet_version: ${{ matrix.puppet_gem_version }} runs_on: ${{ matrix.runs_on }} puppetlabs-puppet-strings-a4be216/.github/workflows/release.yml000066400000000000000000000005721466634474300250660ustar00rootroot00000000000000name: "Release" on: workflow_dispatch: inputs: target: description: "The target for the release. This can be a commit sha or a branch." required: false default: "main" jobs: release: uses: "puppetlabs/cat-github-actions/.github/workflows/gem_release.yml@main" with: target: "${{ github.event.inputs.target }}" secrets: "inherit" puppetlabs-puppet-strings-a4be216/.github/workflows/release_prep.yml000066400000000000000000000010231466634474300261040ustar00rootroot00000000000000name: "Release Prep" on: workflow_dispatch: inputs: target: description: "The target for the release. This can be a commit sha or a branch." required: false default: "main" version: description: "Version of gem to be released." required: true jobs: release_prep: uses: "puppetlabs/cat-github-actions/.github/workflows/gem_release_prep.yml@main" with: target: "${{ github.event.inputs.target }}" version: "${{ github.event.inputs.version }}" secrets: "inherit" puppetlabs-puppet-strings-a4be216/.gitignore000066400000000000000000000010431466634474300213100ustar00rootroot00000000000000## MAC OS .DS_Store ## TEXTMATE *.tmproj tmtags ## EMACS *~ \#* .\#* ## VIM *.swp /tags ## BUNDLER .bundle Gemfile.local Gemfile.lock ## YARD .yardoc .yardwarns ## MODULE BUILDS **/pkg ## RubyMine /.idea/ ## rvm/rbenv /.ruby-version ## YARD output /doc/ ## Acceptance test artifacts /log/ /*.gem /spec/acceptance/nodesets/ /spec/fixtures/litmus_inventory.yaml /spec/fixtures/modules/ /spec/fixtures/manifests/ /inventory.yaml ## local coverage results /coverage/ ## local rspec config /.rspec-local ## local ruby environment /vendor/ puppetlabs-puppet-strings-a4be216/.rubocop.yml000066400000000000000000000005321466634474300215740ustar00rootroot00000000000000inherit_from: .rubocop_todo.yml require: - rubocop-performance - rubocop-rspec AllCops: Exclude: - Gemfile - Rakefile - spec/fixtures/**/* - vendor/bundle/**/* NewCops: enable SuggestExtensions: false TargetRubyVersion: '2.7' # Disabled Style/ClassAndModuleChildren: Enabled: false Layout/LineLength: Max: 200 puppetlabs-puppet-strings-a4be216/.rubocop_todo.yml000066400000000000000000000136501466634474300226260ustar00rootroot00000000000000# This configuration was generated by # `rubocop --auto-gen-config` # on 2024-01-22 15:21:03 UTC using RuboCop version 1.50.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. # Offense count: 1 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: Severity, Include. # Include: **/*.gemspec Gemspec/RequireMFA: Exclude: - 'puppet-strings.gemspec' # Offense count: 45 # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. Metrics/AbcSize: Max: 95 # Offense count: 10 # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode. # AllowedMethods: refine Metrics/BlockLength: Max: 44 # Offense count: 1 # Configuration parameters: CountBlocks. Metrics/BlockNesting: Max: 4 # Offense count: 5 # Configuration parameters: CountComments, CountAsOne. Metrics/ClassLength: Max: 283 # Offense count: 34 # Configuration parameters: AllowedMethods, AllowedPatterns. Metrics/CyclomaticComplexity: Max: 36 # Offense count: 42 # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. Metrics/MethodLength: Max: 75 # Offense count: 3 # Configuration parameters: CountKeywordArgs. Metrics/ParameterLists: MaxOptionalParameters: 5 Max: 10 # Offense count: 29 # Configuration parameters: AllowedMethods, AllowedPatterns. Metrics/PerceivedComplexity: Max: 37 # Offense count: 2 Naming/AccessorMethodName: Exclude: - 'lib/puppet-strings/yard/handlers/puppet/base.rb' - 'lib/puppet-strings/yard/handlers/ruby/type_base.rb' # Offense count: 1 # Configuration parameters: ExpectMatchingDefinition, CheckDefinitionPathHierarchy, CheckDefinitionPathHierarchyRoots, Regex, IgnoreExecutableScripts, AllowedAcronyms. # CheckDefinitionPathHierarchyRoots: lib, spec, test, src # AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS Naming/FileName: Exclude: - 'lib/puppet-strings.rb' # Offense count: 1 # Configuration parameters: ForbiddenDelimiters. # ForbiddenDelimiters: (?i-mx:(^|\s)(EO[A-Z]{1}|END)(\s|$)) Naming/HeredocDelimiterNaming: Exclude: - 'spec/acceptance/generate_markdown_spec.rb' # Offense count: 24 # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames. # AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to Naming/MethodParameterName: Exclude: - 'lib/puppet-strings/yard/handlers/ruby/data_type_handler.rb' - 'lib/puppet-strings/yard/parsers/puppet/parser.rb' # Offense count: 2 # Configuration parameters: MinSize. Performance/CollectionLiteralInLoop: Exclude: - 'lib/puppet-strings/yard/handlers/ruby/provider_handler.rb' - 'lib/puppet-strings/yard/handlers/ruby/rsapi_handler.rb' # Offense count: 1 RSpec/BeforeAfterAll: Exclude: - '**/spec/spec_helper.rb' - '**/spec/rails_helper.rb' - '**/spec/support/**/*.rb' - 'spec/acceptance/running_strings_generate_spec.rb' # Offense count: 7 # Configuration parameters: Prefixes, AllowedPatterns. # Prefixes: when, with, without RSpec/ContextWording: Exclude: - 'spec/unit/puppet-strings/markdown/base_spec.rb' - 'spec/unit/puppet-strings/yard/handlers/ruby/data_type_handler_spec.rb' - 'spec/unit/puppet-strings/yard/parsers/json/task_statement_spec.rb' - 'spec/unit/puppet-strings/yard/parsers/puppet/parser_spec.rb' # Offense count: 3 # Configuration parameters: IgnoredMetadata. RSpec/DescribeClass: Exclude: - '**/spec/features/**/*' - '**/spec/requests/**/*' - '**/spec/routing/**/*' - '**/spec/system/**/*' - '**/spec/views/**/*' - 'spec/acceptance/generate_json_spec.rb' - 'spec/acceptance/generate_markdown_spec.rb' - 'spec/acceptance/running_strings_generate_spec.rb' # Offense count: 48 # Configuration parameters: CountAsOne. RSpec/ExampleLength: Max: 66 # Offense count: 6 RSpec/ExpectInHook: Exclude: - 'spec/unit/puppet-strings/json_spec.rb' # Offense count: 91 RSpec/MultipleExpectations: Max: 64 # Offense count: 5 # Configuration parameters: AllowedGroups. RSpec/NestedGroups: Max: 4 # Offense count: 2 RSpec/RepeatedExampleGroupDescription: Exclude: - 'spec/unit/puppet-strings/yard/handlers/ruby/function_handler_spec.rb' # Offense count: 20 # Configuration parameters: Include, CustomTransform, IgnoreMethods, IgnoreMetadata. # Include: **/*_spec.rb RSpec/SpecFilePathFormat: Enabled: false # Offense count: 1 Style/ClassVars: Exclude: - 'lib/puppet-strings/yard/templates/default/layout/html/setup.rb' # Offense count: 3 Style/CombinableLoops: Exclude: - 'lib/puppet-strings/markdown.rb' - 'lib/puppet-strings/yard/handlers/ruby/data_type_handler.rb' # Offense count: 1 Style/MixinUsage: Exclude: - 'spec/acceptance/running_strings_generate_spec.rb' # Offense count: 20 # Configuration parameters: AllowedMethods. # AllowedMethods: respond_to_missing? Style/OptionalBooleanParameter: Exclude: - 'lib/puppet-strings.rb' - 'lib/puppet-strings/describe.rb' - 'lib/puppet-strings/yard/code_objects/class.rb' - 'lib/puppet-strings/yard/code_objects/data_type.rb' - 'lib/puppet-strings/yard/code_objects/data_type_alias.rb' - 'lib/puppet-strings/yard/code_objects/defined_type.rb' - 'lib/puppet-strings/yard/code_objects/function.rb' - 'lib/puppet-strings/yard/code_objects/plan.rb' - 'lib/puppet-strings/yard/code_objects/provider.rb' - 'lib/puppet-strings/yard/code_objects/task.rb' - 'lib/puppet-strings/yard/code_objects/type.rb' - 'lib/puppet-strings/yard/handlers/ruby/data_type_handler.rb' - 'lib/puppet-strings/yard/handlers/ruby/function_handler.rb' puppetlabs-puppet-strings-a4be216/.yardopts000066400000000000000000000000721466634474300211670ustar00rootroot00000000000000--exclude lib/puppet-strings/yard/templates/ --no-private puppetlabs-puppet-strings-a4be216/CHANGELOG.md000066400000000000000000000607121466634474300211410ustar00rootroot00000000000000 # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org). ## [v4.1.3](https://github.com/puppetlabs/puppet-strings/tree/v4.1.3) - 2024-09-05 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v4.1.2...v4.1.3) ### Fixed - (bug) - Pin yard to < 0.9.37 [#401](https://github.com/puppetlabs/puppet-strings/pull/401) ([jordanbreen28](https://github.com/jordanbreen28)) - validate: give hint on how to regenerate outdated REFERENCE.md [#388](https://github.com/puppetlabs/puppet-strings/pull/388) ([kenyon](https://github.com/kenyon)) - (CAT-1688) Upgrade rubocop to `~> 1.50.0` [#383](https://github.com/puppetlabs/puppet-strings/pull/383) ([LukasAud](https://github.com/LukasAud)) - Allow numerics for templates using code_maybe_block [#382](https://github.com/puppetlabs/puppet-strings/pull/382) ([seanmil](https://github.com/seanmil)) ## [v4.1.2](https://github.com/puppetlabs/puppet-strings/tree/v4.1.2) - 2023-12-05 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v4.1.1...v4.1.2) ### Fixed - Revert "(maint) - fix rubocop" Leading argument with delegation syntax not supported with ruby 2.7.0 [#376](https://github.com/puppetlabs/puppet-strings/pull/376) ([jordanbreen28](https://github.com/jordanbreen28)) ## [v4.1.1](https://github.com/puppetlabs/puppet-strings/tree/v4.1.1) - 2023-11-22 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v4.1.0...v4.1.1) ### Fixed - Fix option tag handling with no data types [#361](https://github.com/puppetlabs/puppet-strings/pull/361) ([seanmil](https://github.com/seanmil)) ## [v4.1.0](https://github.com/puppetlabs/puppet-strings/tree/v4.1.0) - 2023-07-04 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v4.0.0...v4.1.0) ### Added - (CONT-1193) - Add `--providers` and `--list-providers` flags [#357](https://github.com/puppetlabs/puppet-strings/pull/357) ([jordanbreen28](https://github.com/jordanbreen28)) ## [v4.0.0](https://github.com/puppetlabs/puppet-strings/tree/v4.0.0) - 2023-04-25 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v4.0.0.rc.1...v4.0.0) ## [v4.0.0.rc.1](https://github.com/puppetlabs/puppet-strings/tree/v4.0.0.rc.1) - 2023-04-17 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v3.0.1...v4.0.0.rc.1) ### Changed - (CONT-812) Puppet 8 / Ruby 3 support [#348](https://github.com/puppetlabs/puppet-strings/pull/348) ([chelnak](https://github.com/chelnak)) ### Added - Add deprecated tag [#342](https://github.com/puppetlabs/puppet-strings/pull/342) ([b4ldr](https://github.com/b4ldr)) ## [v3.0.1](https://github.com/puppetlabs/puppet-strings/tree/v3.0.1) - 2022-10-25 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v3.0.0...v3.0.1) ### Fixed - (GH-332) Ensure PuppetStrings is loaded for tasks [#333](https://github.com/puppetlabs/puppet-strings/pull/333) ([chelnak](https://github.com/chelnak)) ## [v3.0.0](https://github.com/puppetlabs/puppet-strings/tree/v3.0.0) - 2022-10-21 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v2.9.0...v3.0.0) ### Changed - (CONT-228) Remove deprecated emit flags [#329](https://github.com/puppetlabs/puppet-strings/pull/329) ([chelnak](https://github.com/chelnak)) - (CONT-228) Bump ruby version [#326](https://github.com/puppetlabs/puppet-strings/pull/326) ([chelnak](https://github.com/chelnak)) - (#301) Update minimum Ruby version to 2.5.0 [#313](https://github.com/puppetlabs/puppet-strings/pull/313) ([danielparks](https://github.com/danielparks)) ### Added - (#223) Use code blocks as appropriate in Markdown [#319](https://github.com/puppetlabs/puppet-strings/pull/319) ([danielparks](https://github.com/danielparks)) - Use tilde heredocs for readability [#317](https://github.com/puppetlabs/puppet-strings/pull/317) ([danielparks](https://github.com/danielparks)) ### Fixed - (#240) Fix output of default values that are expressions [#315](https://github.com/puppetlabs/puppet-strings/pull/315) ([danielparks](https://github.com/danielparks)) - (#267) Don’t show “Public X” header without contents [#314](https://github.com/puppetlabs/puppet-strings/pull/314) ([danielparks](https://github.com/danielparks)) - (#307) Always enable plan parsing [#312](https://github.com/puppetlabs/puppet-strings/pull/312) ([danielparks](https://github.com/danielparks)) - (#302) Fix warnings generated by ERB.new [#308](https://github.com/puppetlabs/puppet-strings/pull/308) ([danielparks](https://github.com/danielparks)) - (#304) Fix double backticks in Markdown [#305](https://github.com/puppetlabs/puppet-strings/pull/305) ([danielparks](https://github.com/danielparks)) - (#300) Fix anchor links in Markdown docs [#303](https://github.com/puppetlabs/puppet-strings/pull/303) ([danielparks](https://github.com/danielparks)) ## [v2.9.0](https://github.com/puppetlabs/puppet-strings/tree/v2.9.0) - 2021-11-29 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v2.8.0...v2.9.0) ### Added - Implement a strings:validate:reference task [#291](https://github.com/puppetlabs/puppet-strings/pull/291) ([ekohl](https://github.com/ekohl)) ### Fixed - Fix rare undefined method `any?' for nil:NilClass error [#289](https://github.com/puppetlabs/puppet-strings/pull/289) ([sanfrancrisko](https://github.com/sanfrancrisko)) ## [v2.8.0](https://github.com/puppetlabs/puppet-strings/tree/v2.8.0) - 2021-07-19 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v2.7.0...v2.8.0) ### Added - (DOCUMENT-1232) Add support for ensurable in types_extras_handler [#281](https://github.com/puppetlabs/puppet-strings/pull/281) ([joshcooper](https://github.com/joshcooper)) ### Fixed - (FIXUP) Check for nil before injecting provider param into Types [#285](https://github.com/puppetlabs/puppet-strings/pull/285) ([scotje](https://github.com/scotje)) - README.md: update link to docs [#276](https://github.com/puppetlabs/puppet-strings/pull/276) ([kenyon](https://github.com/kenyon)) ## [v2.7.0](https://github.com/puppetlabs/puppet-strings/tree/v2.7.0) - 2021-05-17 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v2.6.0...v2.7.0) ### Fixed - Only set tasks = true when parsing plans. [#266](https://github.com/puppetlabs/puppet-strings/pull/266) ([binford2k](https://github.com/binford2k)) ## [v2.6.0](https://github.com/puppetlabs/puppet-strings/tree/v2.6.0) - 2021-01-18 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v2.5.0...v2.6.0) ### Changed - (MAINT) Drop Ruby 2.1.x and Puppet 4.x compatibility [#253](https://github.com/puppetlabs/puppet-strings/pull/253) ([scotje](https://github.com/scotje)) ### Added - Improved markdown templates [#252](https://github.com/puppetlabs/puppet-strings/pull/252) ([kozl](https://github.com/kozl)) ### Fixed - Do not fail in case return tag has no type specified [#268](https://github.com/puppetlabs/puppet-strings/pull/268) ([tiandrey](https://github.com/tiandrey)) - Handle a missing description gracefully [#260](https://github.com/puppetlabs/puppet-strings/pull/260) ([scotje](https://github.com/scotje)) - Fix ERB failure - parameters without descriptions [#255](https://github.com/puppetlabs/puppet-strings/pull/255) ([trevor-vaughan](https://github.com/trevor-vaughan)) - puppet_function template: fix tags, source [#249](https://github.com/puppetlabs/puppet-strings/pull/249) ([raemer](https://github.com/raemer)) - Handle a missing description gracefully [#246](https://github.com/puppetlabs/puppet-strings/pull/246) ([ekohl](https://github.com/ekohl)) ## [v2.5.0](https://github.com/puppetlabs/puppet-strings/tree/v2.5.0) - 2020-07-15 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v2.4.0...v2.5.0) ### Added - (GH-225) Document functions in Puppet Datatypes [#235](https://github.com/puppetlabs/puppet-strings/pull/235) ([glennsarti](https://github.com/glennsarti)) - Add checks to resource_type handler and code objects [#232](https://github.com/puppetlabs/puppet-strings/pull/232) ([scotje](https://github.com/scotje)) - (#227) Inject `provider` into params list for types with providers [#231](https://github.com/puppetlabs/puppet-strings/pull/231) ([scotje](https://github.com/scotje)) ### Fixed - (#242) Wrap names in backticks when rendering to markdown [#243](https://github.com/puppetlabs/puppet-strings/pull/243) ([scotje](https://github.com/scotje)) - Eliminate trailing spaces w/o descriptions [#224](https://github.com/puppetlabs/puppet-strings/pull/224) ([binford2k](https://github.com/binford2k)) ## [v2.4.0](https://github.com/puppetlabs/puppet-strings/tree/v2.4.0) - 2020-02-20 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v2.3.1...v2.4.0) ### Added - Add missing HTML output support for enum tag [#218](https://github.com/puppetlabs/puppet-strings/pull/218) ([seanmil](https://github.com/seanmil)) - (PDOC-295) Add @enum tag support for Enum data types [#215](https://github.com/puppetlabs/puppet-strings/pull/215) ([seanmil](https://github.com/seanmil)) - Expanded default search glob for plans. [#214](https://github.com/puppetlabs/puppet-strings/pull/214) ([Raskil](https://github.com/Raskil)) ## [v2.3.1](https://github.com/puppetlabs/puppet-strings/tree/v2.3.1) - 2019-09-23 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v2.3.0...v2.3.1) ### Fixed - (maint) Use parameters method instead of json['parameters'] [#211](https://github.com/puppetlabs/puppet-strings/pull/211) ([lucywyman](https://github.com/lucywyman)) - (PDOC-285) Fix data_type_handler for errors and numbers [#209](https://github.com/puppetlabs/puppet-strings/pull/209) ([glennsarti](https://github.com/glennsarti)) ## [v2.3.0](https://github.com/puppetlabs/puppet-strings/tree/v2.3.0) - 2019-07-17 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v2.2.0...v2.3.0) ### Added - Add Puppet Data Type documentation [#199](https://github.com/puppetlabs/puppet-strings/pull/199) ([glennsarti](https://github.com/glennsarti)) ### Fixed - (PDOC-283) Fix namespaced symbols [#205](https://github.com/puppetlabs/puppet-strings/pull/205) ([glennsarti](https://github.com/glennsarti)) ## [v2.2.0](https://github.com/puppetlabs/puppet-strings/tree/v2.2.0) - 2019-04-05 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/v2.1.0...v2.2.0) ### Added - (PDOC-272) Add required features attribute [#194](https://github.com/puppetlabs/puppet-strings/pull/194) ([kris-bosland](https://github.com/kris-bosland)) - (maint) Implement a strings:generate:reference task [#192](https://github.com/puppetlabs/puppet-strings/pull/192) ([ekohl](https://github.com/ekohl)) - (PDOC-265) Add examples to function reference docs [#188](https://github.com/puppetlabs/puppet-strings/pull/188) ([ekohl](https://github.com/ekohl)) - (PDOC-252) Add describe features to puppet-strings face [#183](https://github.com/puppetlabs/puppet-strings/pull/183) ([kris-bosland](https://github.com/kris-bosland)) ### Fixed - (PDOC-266) Silence 'unexpected construct regexp_literal' warning [#189](https://github.com/puppetlabs/puppet-strings/pull/189) ([seanmil](https://github.com/seanmil)) ## [v2.1.0](https://github.com/puppetlabs/puppet-strings/tree/v2.1.0) - 2018-06-26 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/2.0.0...v2.1.0) ### Added - (PDOC-212, PDOC-213) add support for @note and @todo [#182](https://github.com/puppetlabs/puppet-strings/pull/182) ([eputnam](https://github.com/eputnam)) - (PDOC-255) markdown table of contents update [#181](https://github.com/puppetlabs/puppet-strings/pull/181) ([eputnam](https://github.com/eputnam)) ### Fixed - (PDOC-259) relax ruby requirement to 2.1.0 from 2.1.9 [#184](https://github.com/puppetlabs/puppet-strings/pull/184) ([DavidS](https://github.com/DavidS)) ## [2.0.0](https://github.com/puppetlabs/puppet-strings/tree/2.0.0) - 2018-05-11 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/1.2.1...2.0.0) ### Changed - bump required ruby and puppet versions [#178](https://github.com/puppetlabs/puppet-strings/pull/178) ([eputnam](https://github.com/eputnam)) ### Added - (PDOC-238) add generated message to markdown [#175](https://github.com/puppetlabs/puppet-strings/pull/175) ([eputnam](https://github.com/eputnam)) - (PDOC-228) puppet plan support [#168](https://github.com/puppetlabs/puppet-strings/pull/168) ([eputnam](https://github.com/eputnam)) - (PDOC-206) support for tasks [#161](https://github.com/puppetlabs/puppet-strings/pull/161) ([eputnam](https://github.com/eputnam)) ### Fixed - (PDOC-36) fix hack for README urls [#176](https://github.com/puppetlabs/puppet-strings/pull/176) ([eputnam](https://github.com/eputnam)) - (PDOC-240) add handling for :array node type in rsapi_handler [#174](https://github.com/puppetlabs/puppet-strings/pull/174) ([eputnam](https://github.com/eputnam)) - (PDOC-159) server urls fix [#173](https://github.com/puppetlabs/puppet-strings/pull/173) ([eputnam](https://github.com/eputnam)) - (maint) display Plans in markdown table of contents [#171](https://github.com/puppetlabs/puppet-strings/pull/171) ([eputnam](https://github.com/eputnam)) - (PDOC-233) markdown whitespace fixes [#170](https://github.com/puppetlabs/puppet-strings/pull/170) ([JohnLyman](https://github.com/JohnLyman)) - (PDOC-229) fix error with return_type and @return [#169](https://github.com/puppetlabs/puppet-strings/pull/169) ([eputnam](https://github.com/eputnam)) - (PDOC-36) hack to fix README links in generated HTML [#167](https://github.com/puppetlabs/puppet-strings/pull/167) ([eputnam](https://github.com/eputnam)) - (PDOC-192) remove warning for title/name [#166](https://github.com/puppetlabs/puppet-strings/pull/166) ([eputnam](https://github.com/eputnam)) - (maint) add condition for misleading warning [#155](https://github.com/puppetlabs/puppet-strings/pull/155) ([eputnam](https://github.com/eputnam)) ## [1.2.1](https://github.com/puppetlabs/puppet-strings/tree/1.2.1) - 2018-03-01 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/1.2.0...1.2.1) ### Fixed - (PDOC-224) Handle --emit-json(-stdout) again [#162](https://github.com/puppetlabs/puppet-strings/pull/162) ([ekohl](https://github.com/ekohl)) ## [1.2.0](https://github.com/puppetlabs/puppet-strings/tree/1.2.0) - 2018-02-28 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/1.1.1...1.2.0) ### Added - (PDOC-184) generate markdown [#156](https://github.com/puppetlabs/puppet-strings/pull/156) ([eputnam](https://github.com/eputnam)) - (PDK-437) Add support for Resource API types [#153](https://github.com/puppetlabs/puppet-strings/pull/153) ([DavidS](https://github.com/DavidS)) ### Fixed - Fix return type matching for Puppet functions [#159](https://github.com/puppetlabs/puppet-strings/pull/159) ([pegasd](https://github.com/pegasd)) - Add rgen as a runtime dependency [#149](https://github.com/puppetlabs/puppet-strings/pull/149) ([rnelson0](https://github.com/rnelson0)) ## [1.1.1](https://github.com/puppetlabs/puppet-strings/tree/1.1.1) - 2017-10-20 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/1.1.0...1.1.1) ### Fixed - (PDOC-160) Remove the timestamp from output [#137](https://github.com/puppetlabs/puppet-strings/pull/137) ([GeoffWilliams](https://github.com/GeoffWilliams)) - Fix args handling for rake strings::generate [#136](https://github.com/puppetlabs/puppet-strings/pull/136) ([hashar](https://github.com/hashar)) ## [1.1.0](https://github.com/puppetlabs/puppet-strings/tree/1.1.0) - 2017-03-20 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/1.0.0...1.1.0) ### Added - (PDOC-161) Add `summary` tag for short descriptions [#138](https://github.com/puppetlabs/puppet-strings/pull/138) ([whopper](https://github.com/whopper)) - (PDOC-155) Allow type documentation in Puppet 4 code [#132](https://github.com/puppetlabs/puppet-strings/pull/132) ([whopper](https://github.com/whopper)) ## [1.0.0](https://github.com/puppetlabs/puppet-strings/tree/1.0.0) - 2016-11-28 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/0.99.0...1.0.0) ### Added - (PDOC-136) Detect return type syntax in Puppet Language functions [#126](https://github.com/puppetlabs/puppet-strings/pull/126) ([whopper](https://github.com/whopper)) - (PDOC-135) Detect `return_type` calls in 4.x function dispatches [#125](https://github.com/puppetlabs/puppet-strings/pull/125) ([whopper](https://github.com/whopper)) - (PDOC-121) Include tag or SHA in gh_pages task commit [#121](https://github.com/puppetlabs/puppet-strings/pull/121) ([whopper](https://github.com/whopper)) - (PDOC-125) Display all puppet function signatures in top-level signature key [#119](https://github.com/puppetlabs/puppet-strings/pull/119) ([whopper](https://github.com/whopper)) ### Fixed - (PDOC-93) Ensure search bar doesn't overlap item list in nav bar [#123](https://github.com/puppetlabs/puppet-strings/pull/123) ([whopper](https://github.com/whopper)) - (PDOC-129) Include tags in overload objects when serialized as JSON [#122](https://github.com/puppetlabs/puppet-strings/pull/122) ([whopper](https://github.com/whopper)) - (PDOC-126) Remove `%Q` ruby quotation syntax from parsed strings [#118](https://github.com/puppetlabs/puppet-strings/pull/118) ([whopper](https://github.com/whopper)) - (PDOC-127) Strip whitespace from type feature docstrings [#112](https://github.com/puppetlabs/puppet-strings/pull/112) ([whopper](https://github.com/whopper)) - (PDOC-95) Properly group and display multiple provider `defaultfor`s [#111](https://github.com/puppetlabs/puppet-strings/pull/111) ([whopper](https://github.com/whopper)) - (PDOC-122) Properly parse `newfunction` calls with newlines [#110](https://github.com/puppetlabs/puppet-strings/pull/110) ([whopper](https://github.com/whopper)) ## [0.99.0](https://github.com/puppetlabs/puppet-strings/tree/0.99.0) - 2016-10-10 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/0.4.0...0.99.0) ### Fixed - (PDOC-80) Remove runtime dependency on puppet [#103](https://github.com/puppetlabs/puppet-strings/pull/103) ([whopper](https://github.com/whopper)) - (PDOC-63) Code refactoring, fix up, and lots of new functionality. [#98](https://github.com/puppetlabs/puppet-strings/pull/98) ([peterhuene](https://github.com/peterhuene)) - (PDOC-71) Workaround for spurious error failures [#90](https://github.com/puppetlabs/puppet-strings/pull/90) ([trevor-vaughan](https://github.com/trevor-vaughan)) - Add Puppet type name in front of the provider name [#80](https://github.com/puppetlabs/puppet-strings/pull/80) ([dmitryilyin](https://github.com/dmitryilyin)) ## [0.4.0](https://github.com/puppetlabs/puppet-strings/tree/0.4.0) - 2016-03-30 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/0.3.1...0.4.0) ### Fixed - (PDOC-75) Work with both versions of 'interpret_any' [#77](https://github.com/puppetlabs/puppet-strings/pull/77) ([HAIL9000](https://github.com/HAIL9000)) - (PDOC-70) Always generate the JSON doc when running the rake task [#72](https://github.com/puppetlabs/puppet-strings/pull/72) ([garethr](https://github.com/garethr)) - Fix issue running strings:generate without a yardopts file [#71](https://github.com/puppetlabs/puppet-strings/pull/71) ([garethr](https://github.com/garethr)) - (PDOC-23) Emit json [#55](https://github.com/puppetlabs/puppet-strings/pull/55) ([iankronquist](https://github.com/iankronquist)) ## [0.3.1](https://github.com/puppetlabs/puppet-strings/tree/0.3.1) - 2015-09-22 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/0.3.0...0.3.1) ### Fixed - make metadata match pmt output [#65](https://github.com/puppetlabs/puppet-strings/pull/65) ([underscorgan](https://github.com/underscorgan)) - Last PR for the Summer [#62](https://github.com/puppetlabs/puppet-strings/pull/62) ([iankronquist](https://github.com/iankronquist)) - Same name type and provider [#61](https://github.com/puppetlabs/puppet-strings/pull/61) ([iankronquist](https://github.com/iankronquist)) ## [0.3.0](https://github.com/puppetlabs/puppet-strings/tree/0.3.0) - 2015-09-21 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/0.2.0...0.3.0) ### Added - Actually/pdoc 19 [#36](https://github.com/puppetlabs/puppet-strings/pull/36) ([iankronquist](https://github.com/iankronquist)) - Type checking/pdoc 21 [#35](https://github.com/puppetlabs/puppet-strings/pull/35) ([iankronquist](https://github.com/iankronquist)) - Dispatch params/pdoc 37 [#33](https://github.com/puppetlabs/puppet-strings/pull/33) ([iankronquist](https://github.com/iankronquist)) ### Fixed - Types and providers fixes [#60](https://github.com/puppetlabs/puppet-strings/pull/60) ([iankronquist](https://github.com/iankronquist)) - (PDOC-35) Format generated html properly [#59](https://github.com/puppetlabs/puppet-strings/pull/59) ([iankronquist](https://github.com/iankronquist)) - (PDOC-49) Improve warnings [#57](https://github.com/puppetlabs/puppet-strings/pull/57) ([iankronquist](https://github.com/iankronquist)) - (PDOC-45) Puppet 4x functions handle unusual names [#53](https://github.com/puppetlabs/puppet-strings/pull/53) ([iankronquist](https://github.com/iankronquist)) - (MAINT) Add a space between a parameter name type and its description [#51](https://github.com/puppetlabs/puppet-strings/pull/51) ([roidelapluie](https://github.com/roidelapluie)) - (PDOC-38) Prevent warnings from being issued twice [#50](https://github.com/puppetlabs/puppet-strings/pull/50) ([iankronquist](https://github.com/iankronquist)) - (PDOC-21) Duplicate warnings [#49](https://github.com/puppetlabs/puppet-strings/pull/49) ([iankronquist](https://github.com/iankronquist)) - (PDOC-21) Only create HostClass parameters once [#48](https://github.com/puppetlabs/puppet-strings/pull/48) ([iankronquist](https://github.com/iankronquist)) - (PDOC-35) Support types and providers [#46](https://github.com/puppetlabs/puppet-strings/pull/46) ([iankronquist](https://github.com/iankronquist)) - (maint) Don't print extraneous "true". [#45](https://github.com/puppetlabs/puppet-strings/pull/45) ([iankronquist](https://github.com/iankronquist)) - (PDOC-21) Check mismatched types in defined types [#44](https://github.com/puppetlabs/puppet-strings/pull/44) ([iankronquist](https://github.com/iankronquist)) - Forgot defined types [#42](https://github.com/puppetlabs/puppet-strings/pull/42) ([iankronquist](https://github.com/iankronquist)) - Nested classes/pdoc 35 [#41](https://github.com/puppetlabs/puppet-strings/pull/41) ([iankronquist](https://github.com/iankronquist)) - (maint) Remove unused code path [#38](https://github.com/puppetlabs/puppet-strings/pull/38) ([iankronquist](https://github.com/iankronquist)) - (PDOC-30) Fix Markdown parsing lists parsing [#37](https://github.com/puppetlabs/puppet-strings/pull/37) ([iankronquist](https://github.com/iankronquist)) - (PDOC-37) Warn when documented name does not match declared name [#31](https://github.com/puppetlabs/puppet-strings/pull/31) ([iankronquist](https://github.com/iankronquist)) ## [0.2.0](https://github.com/puppetlabs/puppet-strings/tree/0.2.0) - 2015-03-17 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/0.1.1...0.2.0) ### Added - (PDOC-27) Don't require options for 3x functions [#26](https://github.com/puppetlabs/puppet-strings/pull/26) ([HAIL9000](https://github.com/HAIL9000)) - (PDOC-24) Add basic templates for functions [#22](https://github.com/puppetlabs/puppet-strings/pull/22) ([HAIL9000](https://github.com/HAIL9000)) - (PDOC-17) Add support for YARD tags in puppet code [#21](https://github.com/puppetlabs/puppet-strings/pull/21) ([HAIL9000](https://github.com/HAIL9000)) ### Fixed - Make the metadata match what's generated by the PMT [#28](https://github.com/puppetlabs/puppet-strings/pull/28) ([underscorgan](https://github.com/underscorgan)) - (PDOC-25) Fix mangled puppet namespaces [#27](https://github.com/puppetlabs/puppet-strings/pull/27) ([HAIL9000](https://github.com/HAIL9000)) - (PDOC-26) Rename Puppetx to PuppetX [#25](https://github.com/puppetlabs/puppet-strings/pull/25) ([HAIL9000](https://github.com/HAIL9000)) ## [0.1.1](https://github.com/puppetlabs/puppet-strings/tree/0.1.1) - 2014-10-21 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/0.1.0...0.1.1) ### Fixed - (PDOC-14) Fix strings to work with future parser [#19](https://github.com/puppetlabs/puppet-strings/pull/19) ([HAIL9000](https://github.com/HAIL9000)) ## [0.1.0](https://github.com/puppetlabs/puppet-strings/tree/0.1.0) - 2014-10-07 [Full Changelog](https://github.com/puppetlabs/puppet-strings/compare/a9408c792ba48ffc5e59d8641a538a83197b7064...0.1.0) puppetlabs-puppet-strings-a4be216/CODEOWNERS000066400000000000000000000001101466634474300207050ustar00rootroot00000000000000# Setting ownership to the tooling team * @puppetlabs/devx @bastelfreak puppetlabs-puppet-strings-a4be216/CONTRIBUTING.md000066400000000000000000000131201466634474300215500ustar00rootroot00000000000000# How to contribute Third-party patches are essential for keeping Puppet Strings great. We want to keep it as easy as possible to contribute changes that get things working in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things. ## Getting Started * Make sure you have a [GitHub account](https://github.com/signup/free) * Submit a ticket for your issue, assuming one does not already exist. * Clearly describe the issue including steps to reproduce when it is a bug. * Make sure you fill in the earliest version that you know has the issue. * Fork the repository on GitHub ## Submit an issue We use GitHub Issues for issue tracking on puppet-strings. Before you submit your issue, take a minute to... 1. **Use the GitHub issue search** — check if the issue has already been reported. 2. **Check if the issue has been fixed** — try to reproduce it using the latest `main` or release tag. A good bug report shouldn't leave others needing to chase you up for more information. Please try to be as **detailed as possible** in your issue. What is your environment? What steps will reproduce the issue? Example: > Short and descriptive example issue title > > A summary of the issue with details about the environment it occurs in (Ruby version, Puppet version, Strings version, etc). If > suitable, include the steps required to reproduce the bug. > > 1. This is the first step > 2. This is the second step > 3. Further steps, etc. > > Any other information you want to share that is relevant to the issue being > reported. This might include the lines of code that you have identified as > causing the bug, and potential solutions (and your opinions on their > merits). ## Making Changes * Create a topic branch from where you want to base your work. * This is usually the main branch. * Only target release branches if you are certain your fix must be on that branch. * To quickly create a topic branch based on main; `git checkout -b fix/main/my_contribution main`. Please avoid working directly on the `main` branch. * Make commits of logical units. * Check for unnecessary whitespace with `git diff --check` before committing. * Make sure your commit messages are in the proper format. ```` (PDOC-123) Make the example in CONTRIBUTING imperative and concrete Without this patch applied the example commit message in the CONTRIBUTING document is not a concrete example. This is a problem because the contributor is left to imagine what the commit message should look like based on a description rather than an example. This patch fixes the problem by making the example concrete and imperative. The first line is a real life imperative statement with a ticket number from our issue tracker. The body describes the behavior without the patch, why this is a problem, and how the patch fixes the problem when applied. ```` * Make sure you have added the necessary tests for your changes. * Run _all_ the tests to assure nothing else was accidentally broken. ## Making Trivial Changes ### Documentation For changes of a trivial nature to comments and documentation, it is not always necessary to create a new ticket in Jira. In this case, it is appropriate to start the first line of a commit with '(doc)' instead of a ticket number. ```` (doc) Add documentation commit example to CONTRIBUTING There is no example for contributing a documentation commit to the Puppet repository. This is a problem because the contributor is left to assume how a commit of this nature may appear. The first line is a real life imperative statement with '(doc)' in place of what would have been the ticket number in a non-documentation related commit. The body describes the nature of the new documentation or comments added. ```` ## Submitting Changes * Sign the [Contributor License Agreement](http://links.puppet.com/cla). * Push your changes to a topic branch in your fork of the repository. * Submit a pull request to the repository in the puppetlabs organization. * Update your Jira ticket to mark that you have submitted code and are ready for it to be reviewed (Status: Ready for Merge). * Include a link to the pull request in the ticket. * After feedback has been given we expect responses within two weeks. After two weeks will may close the pull request if it isn't showing any activity. ## Cutting a release To cut a new release, from a current `main` checkout: * Start the release branch with `git checkout -b release-prep` * Update `lib/puppet-strings/version.rb` to the new version * Update the CHANGELOG * Have a [CHANGELOG_GITHUB_TOKEN](https://github.com/skywinder/github-changelog-generator#github-token) set in your environment * run `rake changelog` * double check the PRs to make sure they're all tagged correctly (using the new CHANGELOG for cross-checking) * Check README and other materials for up-to-date-ness * Commit changes with title "Release prep for v\" * Upload and PR the release-prep branch to the puppetlabs GitHub repo * Check that CI is green and merge the PR * Run `rake release[upstream]` to release from your checkout * make sure to use the name of your git remote pointing to the puppetlabs GitHub repo * Remove the release-prep branch # Additional Resources * [More information on contributing](http://links.puppet.com/contribute-to-puppet) * [Contributor License Agreement](http://links.puppet.com/cla) * [General GitHub documentation](http://help.github.com/) * [GitHub pull request documentation](http://help.github.com/send-pull-requests/) puppetlabs-puppet-strings-a4be216/Gemfile000066400000000000000000000026301466634474300206160ustar00rootroot00000000000000# frozen_string_literal: true source ENV['GEM_SOURCE'] || "https://rubygems.org" gemspec def location_for(place_or_version, fake_version = nil) git_url_regex = %r{\A(?(https?|git)[:@][^#]*)(#(?.*))?} file_url_regex = %r{\Afile:\/\/(?.*)} if place_or_version && (git_url = place_or_version.match(git_url_regex)) [fake_version, { git: git_url[:url], branch: git_url[:branch], require: false }].compact elsif place_or_version && (file_url = place_or_version.match(file_url_regex)) ['>= 0', { path: File.expand_path(file_url[:path]), require: false }] else [place_or_version, { require: false }] end end group :development do gem 'puppet', *location_for(ENV['PUPPET_GEM_VERSION']) gem 'json_spec', '~> 1.1', '>= 1.1.5' gem 'mdl', '~> 0.11.0' gem 'pry', require: false gem 'pry-byebug', require: false gem 'pry-stack_explorer', require: false # Need the following otherwise we end up with puppetlabs_spec_helper 1.1.1 gem 'mocha', '~> 1.0' gem 'puppetlabs_spec_helper' gem 'rake' gem 'rspec', '~> 3.1' gem 'rspec-its', '~> 1.0' gem 'rubocop', '~> 1.64.0', require: false gem 'rubocop-performance', '~> 1.16', require: false gem 'rubocop-rspec', '~> 3.0', require: false gem 'serverspec' gem 'simplecov', require: false gem 'simplecov-console', require: false gem 'redcarpet' end group :acceptance do gem 'puppet_litmus' gem 'net-ssh' end puppetlabs-puppet-strings-a4be216/JSON.md000066400000000000000000000706361466634474300204310ustar00rootroot00000000000000Puppet Strings JSON Data ======================== Puppet Strings can generate JSON to STDOUT with the `--format` option: ```shell puppet strings generate --format json ``` Document Schema =============== At the top level, there are nine arrays in the JSON document: | Document Key | Description | | ----------------- | ----------------------------------------------------------------------------- | | puppet_classes | The list of Puppet classes that were parsed. | | data_types | The list of data types that were parsed. | | data_type_aliases | | The list of data types that were parsed. | | defined_types | The list of defined types that were parsed. | | resource_types | The list of resource types that were parsed. | | providers | The list of resource providers that were parsed. | | puppet_functions | The list of Puppet functions (4.x, 4.x and Puppet language) that were parsed. | | puppet_tasks | The list of Puppet tasks that were parsed. | | puppet_plans | The list of Puppet plans that were parsed. | Puppet Classes -------------- Each entry in the `puppet_classes` list is an object with the following attributes: | Attribute Key | Description | | ------------- | ----------------------------------------------------- | | name | The name of the Puppet class. | | file | The file defining the Puppet class. | | line | The line where the Puppet class is defined. | | inherits | The name of the Puppet class the class inherits from. | | docstring | The *DocString* object for the class (see below). | | defaults | The map of parameter names to default values. | | source | The Puppet source code for the class. | Data Types ---------- Each entry in the `data_types` list is an object with the following attributes: | Attribute Key | Description | | ------------- | ----------------------------------------------------------- | | name | The name of the data type. | | file | The file defining the data type. | | line | The line where the data type is data. | | docstring | The *DocString* object for the data type (see below). | | defaults | The map of parameter names to default values. | | source | The ruby source code for the data type. (Not Implemented) | Data Type Aliases ----------------- Each entry in the `data_type_aliases` list is an object with the following attributes: | Attribute Key | Description | | ------------- | ----------------------------------------------------------------- | | name | The name of the data type. | | file | The file defining the data type. | | line | The line where the data type is defined. | | docstring | The *DocString* object for the data type (see below). | | alias_of | The actual type this is an alias of. | | source | The Puppet source code for the data type alias. (Not Implemented) | Defined Types ------------- Each entry in the `defined_types` list is an object with the following attributes: | Attribute Key | Description | | ------------- | -------------------------------------------------------- | | name | The name of the defined type. | | file | The file defining the defined type. | | line | The line where the defined type is defined. | | docstring | The *DocString* object for the defined type (see below). | | defaults | The map of parameter names to default values. | | source | The Puppet source code for the defined type. | Resource Types -------------- Each entry in the `resource_types` list is an object with the following attributes: | Attribute Key | Description | | ------------- | --------------------------------------------------------- | | name | The name of the resource type. | | file | The file defining the resource type. | | line | The line where the resource type is defined. | | docstring | The *DocString* object for the resource type (see below). | | properties | The list of properties for the resource type (see below). | | parameters | The list of parameters for the resource type (see below). | | features | The list of features for the resource type (see below). | Each entry in the `properties` list is an object with the following attributes: | Attribute Key | Description | | ------------- | ------------------------------------------------------- | | name | The name of the property. | | description | The description of the property. | | values | The array of acceptable string values for the property. | | aliases | The map of new values aliased to existing values. | | isnamevar | True if the property is a namevar or false if not. | | default | The default value for the property. | Each entry in the `parameters` list is an object with the following attributes: | Attribute Key | Description | | ------------- | -------------------------------------------------------- | | name | The name of the parameter. | | description | The description of the parameter. | | values | The array of acceptable string values for the parameter. | | aliases | The map of new values aliased to existing values. | | isnamevar | True if the parameter is a namevar or false if not. | | default | The default value for the parameter. | Each entry in the `features` list is an object with the following attributes: | Attribute Key | Description | | ------------- | ------------------------------- | | name | The name of the feature. | | description | The description of the feature. | Providers --------- Each entry in the `providers` list is an object with the following attributes: | Attribute Key | Description | | ------------- | ---------------------------------------------------- | | name | The name of the provider. | | type_name | The name of the resource type of the provider. | | file | The file defining the provider. | | line | The line where the provider is defined. | | docstring | The *DocString* object for the provider (see below). | | confines | The string map of confines for the provider. | | features | The list of features implemented by the provider. | | defaults | The list of lists of "default for" for the provider. | | commands | The string map of commands for the provider. | Puppet Functions ---------------- Each entry in the `puppet_functions` list is an object with the following attributes: | Attribute Key | Description | | ------------- | ----------------------------------------------------------------------------- | | name | The name of the function. | | file | The file defining the function. | | line | The line where the function is defined. | | type | The function type (e.g. ruby3x, ruby4x, puppet). | | signatures | A list of Puppet signatures of the function, including overloads if present. | | docstring | The *DocString* object for the function (see below). | | defaults | The map of parameter names to default values. | | source | The source code for the function. | Puppet Tasks ------------ Each entry in the `puppet_tasks` list is an object with the following attributes: | Attribute Key | Description | | ------------- | ----------------------------------------------------------------------------- | | name | The name of the task. | | file | The file defining the task. | | line | The line where the task is defined. | | docstring | The *DocString* object for the task (see below). | | source | The source code for the task. | | supports_noop | Whether the task supports noop mode | | input_method | Maps to the `input_method` key in the task json | Puppet Plans ------------ Each entry in the `puppet_plans` list is an object with the following attributes: | Attribute Key | Description | | ------------- | ----------------------------------------------------------------------------- | | name | The name of the plan. | | file | The file defining the plan. | | line | The line where the plan is defined. | | docstring | The *DocString* object for the plan (see below). | | defaults | The map of parameter names to default values. | | source | The source code for the plan. | Signature Objects ----------------- The `signatures` key is a function-specific list containing an object for each signature of a function. Each object includes the `signature` itself, as well as each of its `param` and `return` tags. Puppet 4.x functions with overloads will contain multiple signatures, while other function types will contain only one. Each signature is represented as an object with the following attributes: | Attribute Key | Description | | ------------- | -------------------------------------------------------------------------------------------------- | | signature | The signature of the function. | | docstring | The *DocString* object describing the signature, which includes `text`, `param` and `return` tags. | DocString Objects ----------------- For the above types, their docstrings are represented as an object with the following attributes: | Attribute Key | Description | | ------------- | --------------------------------------------------- | | text | The textual part of the DocString. | | tags | The array of tag objects, if any are present. | Each entry in the `tags` list is an object with the following properties: | Attribute Key | Description | | ------------- | ------------------------------------------------------- | | tag_name | The name of the tag (e.g. param, return, etc.). | | text | The descriptive text of the tag. | | types | The array of types associated with the tag. | | name | The name associated with the tag (e.g. parameter name). | For Puppet 4.x functions with overloads, `overload` tags will contain three additional attributes: | Attribute Key | Description | | ------------- | ----------------------------------------------- | | signature | The Puppet signature of the overload. | | docstring | The *DocString* object describing the overload. | | defaults | The map of parameter names to default values. | Example JSON Document --------------------- An example JSON document describing a Puppet class, defined type, resource type, provider, and Puppet functions: ```json { "puppet_classes": [ { "name": "foo", "file": "site.pp", "line": 5, "inherits": "foo::bar", "docstring": { "text": "A simple class.", "tags": [ { "tag_name": "param", "text": "First param.", "types": [ "Integer" ], "name": "param1" }, { "tag_name": "param", "text": "Second param.", "types": [ "Any" ], "name": "param2" }, { "tag_name": "param", "text": "Third param.", "types": [ "String" ], "name": "param3" } ] }, "defaults": { "param3": "hi" }, "source": "class foo(Integer $param1, $param2, String $param3 = hi) inherits foo::bar {\n}" } ], "defined_types": [ { "name": "dt", "file": "site.pp", "line": 12, "docstring": { "text": "A simple defined type.", "tags": [ { "tag_name": "param", "text": "First param.", "types": [ "Integer" ], "name": "param1" }, { "tag_name": "param", "text": "Second param.", "types": [ "Any" ], "name": "param2" }, { "tag_name": "param", "text": "Third param.", "types": [ "String" ], "name": "param3" } ] }, "defaults": { "param3": "hi" }, "source": "define dt(Integer $param1, $param2, String $param3 = hi) {\n}" } ], "resource_types": [ { "name": "database", "file": "database.rb", "line": 43, "docstring": { "text": "An example database server resource type." }, "properties": [ { "name": "ensure", "description": "What state the database should be in.", "values": [ "present", "absent", "up", "down" ], "aliases": { "up": "present", "down": "absent" }, "default": "up" }, { "name": "file", "description": "The database file to use." }, { "name": "log_level", "description": "The log level to use.", "values": [ "debug", "warn", "error" ], "default": "warn" } ], "parameters": [ { "name": "address", "description": "The database server name.", "isnamevar": true }, { "name": "encryption_key", "description": "The encryption key to use." }, { "name": "encrypt", "description": "Whether or not to encrypt the database.", "values": [ "true", "false", "yes", "no" ], "default": "false" } ], "features": [ { "name": "encryption", "description": "The provider supports encryption." } ] } ], "providers": [ { "name": "linux", "type_name": "database", "file": "linux.rb", "line": 33, "docstring": { "text": "An example provider on Linux." }, "confines": { "kernel": "Linux", "osfamily": "RedHat" }, "features": [ "implements_some_feature", "some_other_feature" ], "defaults": [ [ [ "kernel", "Linux" ] ], [ [ "osfamily", "RedHat", ], [ "operatingsystemmajrelease", "7" ] ] ], "commands": { "foo": "/usr/bin/foo" } } ], "puppet_functions": [ { "name": "func", "file": "site.pp", "line": 20, "type": "puppet", "signatures": [ { "signature": "func(Integer $param1, Any $param2, String $param3 = hi)", "docstring": { "text": "A simple function.", "tags": [ { "tag_name": "param", "text": "First param.", "types": [ "Integer" ], "name": "param1" }, { "tag_name": "param", "text": "Second param.", "types": [ "Any" ], "name": "param2" }, { "tag_name": "param", "text": "Third param.", "types": [ "String" ], "name": "param3" }, { "tag_name": "return", "text": "Returns nothing.", "types": [ "Undef" ] } ] } } ], "docstring": { "text": "A simple function.", "tags": [ { "tag_name": "param", "text": "First param.", "types": [ "Integer" ], "name": "param1" }, { "tag_name": "param", "text": "Second param.", "types": [ "Any" ], "name": "param2" }, { "tag_name": "param", "text": "Third param.", "types": [ "String" ], "name": "param3" }, { "tag_name": "return", "text": "Returns nothing.", "types": [ "Undef" ] } ] }, "defaults": { "param3": "hi" }, "source": "function func(Integer $param1, $param2, String $param3 = hi) {\n}" }, { "name": "func3x", "file": "func3x.rb", "line": 1, "type": "ruby3x", "signatures": [ { "signature": "func3x(String $first, Any $second)", "docstring": { "text": "An example 3.x function.", "tags": [ { "tag_name": "param", "text": "The first parameter.", "types": [ "String" ], "name": "first" }, { "tag_name": "param", "text": "The second parameter.", "types": [ "Any" ], "name": "second" }, { "tag_name": "return", "text": "Returns nothing.", "types": [ "Undef" ] } ] } } ], "docstring": { "text": "An example 3.x function.", "tags": [ { "tag_name": "param", "text": "The first parameter.", "types": [ "String" ], "name": "first" }, { "tag_name": "param", "text": "The second parameter.", "types": [ "Any" ], "name": "second" }, { "tag_name": "return", "text": "Returns nothing.", "types": [ "Undef" ] } ] }, "source": "Puppet::Parser::Functions.newfunction(:func3x, doc: <<-DOC\nAn example 3.x function.\n@param [String] first The first parameter.\n@param second The second parameter.\n@return [Undef] Returns nothing.\nDOC\n) do |*args|\nend" }, { "name": "func4x", "file": "func4x.rb", "line": 11, "type": "ruby4x", "signatures": [ { "signature": "func4x(Integer $param1, Any $param2, Optional[Array[String]] $param3)", "docstring": { "text": "The first overload.", "tags": [ { "tag_name": "param", "text": "The first parameter.", "types": [ "Integer" ], "name": "param1" }, { "tag_name": "param", "text": "The second parameter.", "types": [ "Any" ], "name": "param2" }, { "tag_name": "param", "text": "The third parameter.", "types": [ "Optional[Array[String]]" ], "name": "param3" }, { "tag_name": "return", "text": "Returns nothing.", "types": [ "Undef" ] } ] } }, { "signature": "func4x(Boolean $param, Callable &$block)", "docstring": { "text": "The second overload.", "tags": [ { "tag_name": "param", "text": "The first parameter.", "types": [ "Boolean" ], "name": "param" }, { "tag_name": "param", "text": "The block parameter.", "types": [ "Callable" ], "name": "&block" }, { "tag_name": "return", "text": "Returns a string.", "types": [ "String" ] } ] } } ], "docstring": { "text": "An example 4.x function.", "tags": [ { "tag_name": "overload", "signature": "func4x(Integer $param1, Any $param2, Optional[Array[String]] $param3)", "docstring": { "text": "The first overload.", "tags": [ { "tag_name": "param", "text": "The first parameter.", "types": [ "Integer" ], "name": "param1" }, { "tag_name": "param", "text": "The second parameter.", "types": [ "Any" ], "name": "param2" }, { "tag_name": "param", "text": "The third parameter.", "types": [ "Optional[Array[String]]" ], "name": "param3" }, { "tag_name": "return", "text": "Returns nothing.", "types": [ "Undef" ] } ] }, "name": "func4x" }, { "tag_name": "overload", "signature": "func4x(Boolean $param, Callable &$block)", "docstring": { "text": "The second overload.", "tags": [ { "tag_name": "param", "text": "The first parameter.", "types": [ "Boolean" ], "name": "param" }, { "tag_name": "param", "text": "The block parameter.", "types": [ "Callable" ], "name": "&block" }, { "tag_name": "return", "text": "Returns a string.", "types": [ "String" ] } ] }, "name": "func4x" } ] }, "source": "Puppet::Functions.create_function(:func4x) do\n # The first overload.\n # @param param1 The first parameter.\n # @param param2 The second parameter.\n # @param param3 The third parameter.\n # @return [Undef] Returns nothing.\n dispatch :foo do\n param 'Integer', :param1\n param 'Any', :param2\n optional_param 'Array[String]', :param3\n end\n\n # The second overload.\n # @param param The first parameter.\n # @param block The block parameter.\n # @return [String] Returns a string.\n dispatch :other do\n param 'Boolean', :param\n block_param\n end\nend" } ], "puppet_tasks": [ { "name": "(stdin)", "file": "(stdin)", "line": 0, "docstring": { "text": "Allows you to backup your database to local file.", "tags": [ { "name": "database", "tag_name": "param", "text": "Database to connect to", "types": [ "Optional[String[1]]" ] }, { "name": "user", "tag_name": "param", "text": "The user", "types": [ "Optional[String[1]]" ] }, { "name": "password", "tag_name": "param", "text": "The password", "types": [ "Optional[String[1]]" ] }, { "name": "sql", "tag_name": "param", "text": "Path to file you want backup to", "types": [ "String[1]" ] } ] }, "source": "{\n \"description\": \"Allows you to backup your database to local file.\",\n \"input_method\": \"stdin\",\n \"parameters\": {\n \"database\": {\n \"description\": \"Database to connect to\",\n \"type\": \"Optional[String[1]]\"\n },\n \"user\": {\n \"description\": \"The user\",\n \"type\": \"Optional[String[1]]\"\n },\n \"password\": {\n \"description\": \"The password\",\n \"type\": \"Optional[String[1]]\"\n },\n \"sql\": {\n \"description\": \"Path to file you want backup to\",\n \"type\": \"String[1]\"\n }\n }\n}\n", "supports_noop": false, "input_method": "stdin" } ], "puppet_plans": [ { "name": "plann", "file": "(stdin)", "line": 5, "docstring": { "text": "A simple plan.", "tags": [ { "tag_name": "param", "text": "First param.", "types": [ "String" ], "name": "param1" }, { "tag_name": "param", "text": "Second param.", "types": [ "Any" ], "name": "param2" }, { "tag_name": "param", "text": "Third param.", "types": [ "Integer" ], "name": "param3" } ] }, "defaults": { "param3": "1" }, "source": "plan plann(String $param1, $param2, Integer $param3 = 1) {\n}" } ] } ``` puppetlabs-puppet-strings-a4be216/LICENSE000066400000000000000000000236761466634474300203450ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS puppetlabs-puppet-strings-a4be216/README.md000066400000000000000000000132501466634474300206020ustar00rootroot00000000000000# Puppet strings [![ci](https://github.com/puppetlabs/puppet-strings/actions/workflows/ci.yml/badge.svg)](https://github.com/puppetlabs/puppet-strings/actions/workflows/ci.yml) [![Gem Version](https://badge.fury.io/rb/puppet-strings.svg)](https://badge.fury.io/rb/puppet-strings) [![Code Owners](https://img.shields.io/badge/owners-DevX--team-blue)](https://github.com/puppetlabs/puppet-strings/blob/main/CODEOWNERS) Puppet Strings generates documentation for Puppet code and extensions written in Puppet and Ruby. Strings processes code and YARD-style code comments to create documentation in HTML, Markdown, or JSON formats. ## Installing Puppet Strings ### Requirements * Ruby 2.7.0 or newer * Puppet 7.0.0 or newer ### Install Puppet Strings Installation instructions vary slightly depending on how you have installed Puppet: #### Installing Puppet Strings with [`puppet-agent`](https://puppet.com/docs/puppet/6.4/about_agent.html#what-puppet-agent-and-puppetserver-are) package Install the `puppet-strings` gem into the `puppet-agent` environment: ``` bash sudo /opt/puppetlabs/puppet/bin/gem install puppet-strings ``` #### Installing Puppet Strings with standalone `puppet` gem Install the `puppet-strings` gem into the same Ruby installation where you have installed the `puppet` gem: ``` bash gem install puppet-strings ``` ### Configure Puppet Strings (Optional) To use YARD options with Puppet Strings, specify a `.yardopts` file in the same directory in which you run `puppet strings`. Puppet Strings supports the Markdown format and automatically sets the YARD `markup` option to `markdown`. To see a list of available YARD options, run `yard help doc`. For details about YARD options configuration, see the [YARD docs](http://www.rubydoc.info/gems/yard/file/docs/GettingStarted.md#config). ## Generating documentation with Puppet Strings By default, Puppet Strings outputs documentation as HTML, or you can specify JSON or Markdown output instead. Strings generates reference documentation based on the code and Strings code comments in all Puppet and Ruby source files under the `./manifests/`, `./functions/`, `./lib/`, `./types/`, and `./tasks/` directories. Strings outputs HTML of the reference information and the module README to the module's `./doc/` directory. This output can be rendered in any browser. JSON and Markdown output include the reference documentation only. Strings sends JSON output to either STDOUT or to a file. Markdown output is written to a REFERENCE.md file in the module's main directory. See the [Puppet Strings documentation](https://puppet.com/docs/puppet/latest/puppet_strings.html) for complete instructions for generating documentation with Strings. For code comment style guidelines and examples, see the [Puppet Strings style guide](https://puppet.com/docs/puppet/latest/puppet_strings_style.html). ### Additional Resources Here are a few other good resources for getting started with documentation: * [Module README Template](https://puppet.com/docs/puppet/latest/puppet_strings.html) * [YARD Getting Started Guide](http://www.rubydoc.info/gems/yard/file/docs/GettingStarted.md) * [YARD Tags Overview](http://www.rubydoc.info/gems/yard/file/docs/Tags.md) ## Developing and Contributing We love contributions from the community! If you'd like to contribute to `puppet-strings`, check out [CONTRIBUTING.md](https://github.com/puppetlabs/puppet-strings/blob/main/CONTRIBUTING.md) to get information on the contribution process. ### Running Specs If you plan on developing features or fixing bugs in Puppet Strings, it is essential that you run specs before opening a pull request. To run specs, run the `spec` rake task: ``` bash bundle install --path .bundle/gems bundle exec rake spec ``` ### Running Acceptance Tests Acceptance tests can be executed with [puppet_litmus](https://github.com/puppetlabs/puppet_litmus). An example of running the acceptance tests locally with Docker: 1. Ensure [Docker](https://www.docker.com/products/docker-desktop) is installed and running. 2. Install Ruby gems. This step can be skipped if you have already followed the [Running Specs](#running-specs) instructions. ``` bash bundle install --path .bundle/gems ``` 3. Provision a docker container, in this case CentOS 7 ``` bash bundle exec rake 'litmus:provision[docker, centos:7]' ``` 4. Install test items; Puppet Agent, our test module, and the puppet-strings gem built from this source code ``` bash bundle exec rake 'litmus:install_agent[puppet8]' bundle exec rake 'litmus:install_modules_from_directory[./spec/fixtures/acceptance/modules]' bundle exec rake litmus:install_gems ``` 5. Run the acceptance tests. These tests can be run more than once without the need to run the provisioning steps again ``` bash bundle exec rake litmus:acceptance:parallel ``` 6. Remove any test containers ``` bash bundle exec rake litmus:tear_down ``` ## License This codebase is licensed under Apache 2.0. However, the open source dependencies included in this codebase might be subject to other software licenses such as AGPL, GPL2.0, and MIT. ## Support Please log issues in [GitHub issues](https://github.com/puppetlabs/puppet-strings/issues). Check out [CONTRIBUTING.md](https://github.com/puppetlabs/puppet-strings/blob/main/CONTRIBUTING.md) for tips on writing _the best_ issues. There is also an active community on the [Puppet community Slack](https://slack.puppet.com) in the #forge-modules channel. We use semantic version numbers for our releases and recommend that users upgrade to patch releases and minor releases as they become available. Bug fixes and ongoing development will occur in minor releases for the current major version. puppetlabs-puppet-strings-a4be216/Rakefile000066400000000000000000000022541466634474300207720ustar00rootroot00000000000000# frozen_string_literal: true require 'bundler/gem_tasks' require 'puppet-lint/tasks/puppet-lint' require 'rspec/core/rake_task' require 'puppetlabs_spec_helper/tasks/fixtures' begin require 'puppet_litmus/rake_tasks' rescue LoadError # Gem not present end RSpec::Core::RakeTask.new(:spec) do |t| t.exclude_pattern = "spec/acceptance/**/*.rb" end namespace :spec do desc 'Run RSpec code examples with coverage collection' task :coverage do ENV['COVERAGE'] = 'yes' Rake::Task['spec'].execute end end RSpec::Core::RakeTask.new(:acceptance) do |t| t.pattern = "spec/unit/**/*.rb" end task :spec => :spec_clean task :acceptance => :spec_prep # Add our own tasks require 'puppet-strings/tasks' PuppetLint.configuration.send('disable_80chars') PuppetLint.configuration.ignore_paths = %w(acceptance/**/*.pp spec/**/*.pp pkg/**/*.pp) desc 'Validate Ruby source files and ERB templates.' task :validate do Dir['spec/**/*.rb','lib/**/*.rb'].each do |ruby_file| sh "ruby -c #{ruby_file}" unless /spec\/fixtures/.match?(ruby_file) end Dir['lib/puppet-strings/yard/templates/**/*.erb'].each do |template| sh "erb -P -x -T '-' #{template} | ruby -c" end end puppetlabs-puppet-strings-a4be216/lib/000077500000000000000000000000001466634474300200705ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings.rb000066400000000000000000000060131466634474300234210ustar00rootroot00000000000000# frozen_string_literal: true # The root module for Puppet Strings. module PuppetStrings # The glob patterns used to search for files to document. DEFAULT_SEARCH_PATTERNS = ['manifests/**/*.pp', 'functions/**/*.pp', 'types/**/*.pp', 'lib/**/*.rb', 'tasks/*.json', 'plans/**/*.pp'].freeze # Generates documentation. # @param [Array] search_patterns The search patterns (e.g. manifests/**/*.pp) to look for files. # @param [Hash] options The options hash. # @option options [Boolean] :debug Enable YARD debug output. # @option options [Boolean] :backtrace Enable YARD backtraces. # @option options [String] :markup The YARD markup format to use (defaults to 'markdown'). # @option options [String] :path Write the selected format to a file path # @option options [Boolean] :markdown From the --format option, is the format Markdown? # @option options [Boolean] :json Is the format JSON? # @option options [Array] :yard_args The arguments to pass to yard. # @return [void] def self.generate(search_patterns = DEFAULT_SEARCH_PATTERNS, options = {}) require 'puppet-strings/yard' PuppetStrings::Yard.setup! # Format the arguments to YARD args = ['doc'] args << '--no-progress' args << '--debug' if options[:debug] args << '--backtrace' if options[:debug] args << "-m#{options[:markup] || 'markdown'}" file = nil if options[:json] || options[:markdown] file = if options[:json] options[:path] elsif options[:markdown] options[:path] || 'REFERENCE.md' end # Disable output and prevent stats/progress when writing to STDOUT args << '-n' args << '-q' unless file args << '--no-stats' unless file end yard_args = options[:yard_args] args += yard_args if yard_args args += search_patterns # Run YARD YARD::CLI::Yardoc.run(*args) # If outputting JSON, render the output render_json(file) if options[:json] && !options[:describe] # If outputting Markdown, render the output render_markdown(file) if options[:markdown] return unless options[:describe] render_describe(options[:describe_types], options[:describe_list], options[:providers], options[:list_providers]) end def self.puppet_5? Puppet::Util::Package.versioncmp(Puppet.version, '5.0.0') >= 0 end def self.render_json(path) require 'puppet-strings/json' PuppetStrings::Json.render(path) end def self.render_markdown(path) require 'puppet-strings/markdown' PuppetStrings::Markdown.render(path) end def self.render_describe(describe_types, list = false, show_providers = true, list_providers = false) require 'puppet-strings/describe' PuppetStrings::Describe.render(describe_types, list, show_providers, list_providers) end # Runs the YARD documentation server. # @param [Array] args The arguments to YARD. def self.run_server(*args) require 'puppet-strings/yard' PuppetStrings::Yard.setup! YARD::CLI::Server.run(*args) end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/000077500000000000000000000000001466634474300230745ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/describe.rb000066400000000000000000000064441466634474300252110ustar00rootroot00000000000000# frozen_string_literal: true require 'json' require 'puppet-strings/json' # The module for command line documentation related functionality. module PuppetStrings::Describe # Renders requested types or a summarized list in the current YARD registry to STDOUT. # @param [Array] describe_types The list of names of the types to be displayed. # @param [bool] list_types Create the summarized list instead of describing each type. # @param [bool] show_type_providers Show details of the providers of a specified type. # @param [bool] list_providers Create a summarized list of providers. # @return [void] def self.render(describe_types = [], list_types = false, show_type_providers = true, list_providers = false) document = { defined_types: YARD::Registry.all(:puppet_defined_type).sort_by!(&:name).map!(&:to_hash), resource_types: YARD::Registry.all(:puppet_type).sort_by!(&:name).map!(&:to_hash), providers: YARD::Registry.all(:puppet_provider).sort_by!(&:name).map!(&:to_hash) } # if --list flag passed, produce a summarized list of types if list_types puts 'These are the types known to puppet:' document[:resource_types].each { |t| list_one(t) } # if a type(s) has been passed, show the details of that type(s) elsif describe_types type_names = {} describe_types.each { |name| type_names[name] = true } document[:resource_types].each do |t| show_one_type(t, show_type_providers) if type_names[t[:name].to_s] end # if --providers flag passed, produce a summarized list of providers elsif list_providers puts 'These are the providers known to puppet:' document[:providers].each { |t| list_one(t) } end end def self.show_one_type(resource_type, providers = true) puts format("\n%s\n%s", name: resource_type[:name], underscore: '=' * resource_type[:name].length) puts resource_type[:docstring][:text] combined_list = (resource_type[:parameters].nil? ? [] : resource_type[:parameters]) + (resource_type[:properties].nil? ? [] : resource_type[:properties]) return unless combined_list.any? puts "\nParameters\n----------" combined_list.sort_by { |p| p[:name] }.each { |p| show_one_parameter(p) } return unless providers puts "\nProviders\n---------" resource_type[:providers]&.sort_by { |p| p[:name] }&.each { |p| puts p[:name].to_s.ljust(15) } end def self.show_one_parameter(parameter) puts format("\n- **%s**\n", name: parameter[:name]) puts parameter[:description] puts format('Valid values are `%s`.', values: parameter[:values].join('`, `')) unless parameter[:values].nil? puts format('Requires features %s.', required_features: parameter[:required_features]) unless parameter[:required_features].nil? end def self.list_one(object) targetlength = 48 shortento = targetlength - 4 contentstring = object[:docstring][:text] end_of_line = contentstring.index("\n") # "." gives closer results to old describeb, but breaks for '.k5login' contentstring = contentstring[0..end_of_line] unless end_of_line.nil? contentstring = "#{contentstring[0..shortento]} ..." if contentstring.length > targetlength puts "#{object[:name].to_s.ljust(15)} - #{contentstring}" end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/json.rb000066400000000000000000000026501466634474300243750ustar00rootroot00000000000000# frozen_string_literal: true require 'json' # The module for JSON related functionality. module PuppetStrings::Json # Renders the current YARD registry as JSON to the given file (or STDOUT if nil). # @param [String] file The path to the output file to render the registry to. If nil, output will be to STDOUT. # @return [void] def self.render(file = nil) document = { puppet_classes: YARD::Registry.all(:puppet_class).sort_by!(&:name).map!(&:to_hash), data_types: YARD::Registry.all(:puppet_data_type).sort_by!(&:name).map!(&:to_hash), data_type_aliases: YARD::Registry.all(:puppet_data_type_alias).sort_by!(&:name).map!(&:to_hash), defined_types: YARD::Registry.all(:puppet_defined_type).sort_by!(&:name).map!(&:to_hash), resource_types: YARD::Registry.all(:puppet_type).sort_by!(&:name).map!(&:to_hash), providers: YARD::Registry.all(:puppet_provider).sort_by!(&:name).map!(&:to_hash), puppet_functions: YARD::Registry.all(:puppet_function).sort_by!(&:name).map!(&:to_hash), puppet_tasks: YARD::Registry.all(:puppet_task).sort_by!(&:name).map!(&:to_hash), puppet_plans: YARD::Registry.all(:puppet_plan).sort_by!(&:name).map!(&:to_hash) # TODO: Need Ruby documentation? } if file File.open(file, 'w') do |f| f.write(JSON.pretty_generate(document)) f.write("\n") end else puts JSON.pretty_generate(document) end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown.rb000066400000000000000000000044431466634474300252500ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/json' # module for parsing Yard Registries and generating markdown module PuppetStrings::Markdown require_relative 'markdown/puppet_class' require_relative 'markdown/function' require_relative 'markdown/defined_type' require_relative 'markdown/data_type' require_relative 'markdown/resource_type' require_relative 'markdown/puppet_task' require_relative 'markdown/puppet_plan' # Get classes that handle collecting and rendering each section/group. # # @return [Array[class]] The classes def self.groups [ PuppetStrings::Markdown::PuppetClass, PuppetStrings::Markdown::DefinedType, PuppetStrings::Markdown::ResourceType, PuppetStrings::Markdown::Function, PuppetStrings::Markdown::DataType, PuppetStrings::Markdown::PuppetTask, PuppetStrings::Markdown::PuppetPlan ] end # generates markdown documentation # @return [String] markdown doc def self.generate output = [ "# Reference\n\n", "\n\n", "## Table of Contents\n\n" ] # Create table of contents template = erb(File.join(__dir__, 'markdown', 'templates', 'table_of_contents.erb')) groups.each do |group| group_name = group.group_name items = group.items.map(&:toc_info) has_private = items.any? { |item| item[:private] } has_public = items.any? { |item| !item[:private] } output << template.result(binding) end # Create actual contents groups.each do |group| items = group.items.reject(&:private?) unless items.empty? output << "## #{group.group_name}\n\n" output.append(items.map(&:render)) end end output.join end # mimicks the behavior of the json render, although path will never be nil # @param [String] path path to destination file def self.render(path = nil) if path.nil? puts generate exit else File.write(path, generate) YARD::Logger.instance.debug "Wrote markdown to #{path}" end end # Helper function to load an ERB template. # # @param [String] path The full path to the template file. # @return [ERB] Template def self.erb(path) ERB.new(File.read(path), trim_mode: '-') end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/000077500000000000000000000000001466634474300247165ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/base.rb000066400000000000000000000164241466634474300261640ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings' require 'puppet-strings/json' require 'puppet-strings/yard' require 'puppet-strings/markdown/helpers' # Implements classes that make elements in a YARD::Registry hash easily accessible for template. module PuppetStrings::Markdown # This class makes elements in a YARD::Registry hash easily accessible for templates. # # Here's an example hash: # {:name=>:klass, # :file=>"(stdin)", # :line=>16, # :inherits=>"foo::bar", # :docstring=> # {:text=>"An overview for a simple class.", # :tags=> # [{:tag_name=>"summary", :text=>"A simple class."}, # {:tag_name=>"since", :text=>"1.0.0"}, # {:tag_name=>"see", :name=>"www.puppet.com"}, # {:tag_name=>"deprecated", :text=>"No longer supported and will be removed in a future release"}, # {:tag_name=>"example", # :text=> # "class { 'klass':\n" + # " param1 => 1,\n" + # " param3 => 'foo',\n" + # "}", # :name=>"This is an example"}, # {:tag_name=>"author", :text=>"eputnam"}, # {:tag_name=>"option", :name=>"opts"}, # {:tag_name=>"raise", :text=>"SomeError"}, # {:tag_name=>"param", # :text=>"First param.", # :types=>["Integer"], # :name=>"param1"}, # {:tag_name=>"param", # :text=>"Second param.", # :types=>["Any"], # :name=>"param2"}, # {:tag_name=>"param", # :text=>"Third param.", # :types=>["String"], # :name=>"param3"}]}, # :defaults=>{"param1"=>"1", "param2"=>"undef", "param3"=>"'hi'"}, # :source=> # "class klass (\n" + # " Integer $param1 = 1,\n" + # " $param2 = undef,\n" + # " String $param3 = 'hi'\n" + # ") inherits foo::bar {\n" + # "}"} class Base # Helpers for ERB templates include PuppetStrings::Markdown::Helpers # Set or return the name of the group # # @param [Optional[String]] Name of the group to set # @return [String] Name of the group def self.group_name(name = nil) @group_name = name if name @group_name end # Set or return the types registered with YARD # # @param [Optional[Array[Symbol]]] Array of symbols registered with YARD to set # @return [Array[Symbol]] Array of symbols registered with YARD def self.yard_types(types = nil) @yard_types = types if types @yard_types end # @return [Array] list of items def self.items yard_types .flat_map { |type| YARD::Registry.all(type) } .sort_by(&:name) .map(&:to_hash) .map { |i| new(i) } end def initialize(registry, component_type) @type = component_type @registry = registry @tags = registry[:docstring][:tags] || [] end # generate 1:1 tag methods # e.g. {:tag_name=>"author", :text=>"eputnam"} { return_val: 'return', since: 'since', summary: 'summary', note: 'note', todo: 'todo', deprecated: 'deprecated' }.each do |method_name, tag_name| # @return [String] unless the tag is nil or the string.empty? define_method method_name do @tags.find { |tag| tag[:tag_name] == tag_name && !tag[:text].empty? }[:text] if @tags.any? { |tag| tag[:tag_name] == tag_name && !tag[:text].empty? } end end # @return [String] top-level name def name @registry[:name]&.to_s end # @return [String] 'Overview' text (untagged text) def text @registry[:docstring][:text] unless @registry[:docstring][:text].empty? end # @return [String] data type of return value def return_type @tags.find { |tag| tag[:tag_name] == 'return' }[:types][0] if @tags.any? { |tag| tag[:tag_name] == 'return' } end # @return [String] text from @since tag def since @tags.find { |tag| tag[:tag_name] == 'since' }[:text] if @tags.any? { |tag| tag[:tag_name] == 'since' } end # @return [Array] @see tag hashes def see select_tags('see') end # @return [Array] parameter tag hashes def params tags = @tags.select { |tag| tag[:tag_name] == 'param' }.map do |param| param[:link] = clean_link("$#{name}::#{param[:name]}") param end tags.empty? ? nil : tags end # @return [Array] example tag hashes def examples select_tags('example') end # @return [Array] raise tag hashes def raises select_tags('raise') end # @return [Array] option tag hashes def options select_tags('option') end # @return [Array] enum tag hashes def enums select_tags('enum') end # @param parameter_name # parameter name to match to option tags # @return [Array] option tag hashes that have a parent parameter_name def options_for_param(parameter_name) opts_for_p = options.select { |o| o[:parent] == parameter_name } unless options.nil? opts_for_p unless opts_for_p.nil? || opts_for_p.empty? end # @param parameter_name # parameter name to match to enum tags # @return [Array] enum tag hashes that have a parent parameter_name def enums_for_param(parameter_name) enums_for_p = enums.select { |e| e[:parent] == parameter_name } unless enums.nil? enums_for_p unless enums_for_p.nil? || enums_for_p.empty? end # @return [Hash] any defaults found for the component def defaults @registry[:defaults] unless @registry[:defaults].nil? end # @return [Hash] information needed for the table of contents def toc_info { name: name.to_s, link: link, desc: summary || @registry[:docstring][:text][0..140].tr("\n", ' '), private: private? } end # @return [String] makes the component name suitable for a GitHub markdown link def link clean_link(name) end def private? @tags.any? { |tag| tag[:tag_name] == 'api' && tag[:text] == 'private' } end def word_wrap(text, line_width: 120, break_sequence: "\n") return unless text text.split("\n").map! { |line| line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").strip : line } * break_sequence end # @return [String] full markdown rendering of a component def render(template) file = File.join(File.dirname(__FILE__), 'templates', template) begin PuppetStrings::Markdown.erb(file).result(binding) rescue StandardError => e raise "Processing #{@registry[:file]}:#{@registry[:line]} with #{file} => #{e}" end end private def select_tags(name) tags = @tags.select { |tag| tag[:tag_name] == name } tags.empty? ? nil : tags end # Convert an input into a string appropriate for an anchor name. # # This converts any character not suitable for an id attribute into a '-'. Generally we're running this on Puppet identifiers for types and # variables, so we only need to worry about the special characters ':' and '$'. With namespaces Puppet variables this should always be produce a # unique result from a unique input, since ':' only appears in pairs, '$' only appears at the beginning, and '-' never appears. # # @param [String] the input to convert # @return [String] the anchor-safe string def clean_link(input) input.tr('^a-zA-Z0-9_-', '-') end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/data_type.rb000066400000000000000000000016351466634474300272220ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/markdown/base' module PuppetStrings::Markdown # This class encapsualtes ruby data types and puppet type aliases class DataType < Base attr_reader :alias_of, :functions group_name 'Data types' yard_types %i[puppet_data_type puppet_data_type_alias] def initialize(registry) @template = 'data_type.erb' super(registry, 'data type') @alias_of = registry[:alias_of] unless registry[:alias_of].nil? @functions = @registry[:functions]&.map { |func| DataType::Function.new(func) } end def render super(@template) end end # Generates Markdown for a Puppet Function. class DataType::Function < Base def initialize(registry) super(registry, 'data_type_function') end def render super('data_type_function.erb') end def signature @registry[:signature] end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/defined_type.rb000066400000000000000000000006511466634474300277040ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/markdown/base' module PuppetStrings::Markdown # Generates Markdown for a Puppet Defined Type. class DefinedType < Base group_name 'Defined types' yard_types [:puppet_defined_type] def initialize(registry) @template = 'classes_and_defines.erb' super(registry, 'defined type') end def render super(@template) end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/function.rb000066400000000000000000000022721466634474300270730ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/markdown/base' module PuppetStrings::Markdown # Generates Markdown for a Puppet Function. class Function < Base attr_reader :signatures group_name 'Functions' yard_types [:puppet_function] def initialize(registry) @template = 'function.erb' super(registry, 'function') @signatures = [] registry[:signatures].each do |sig| @signatures.push(Signature.new(sig)) end end def render super(@template) end def type t = @registry[:type] if t.include?('ruby4x') 'Ruby 4.x API' elsif t.include?('ruby3') 'Ruby 3.x API' elsif t.include?('ruby') 'Ruby' else 'Puppet Language' end end def error_type(type) "`#{type.split[0]}`" end def error_text(text) text.split.drop(1).join(' ').to_s end end # Implements methods to retrieve information about a function signature. class Function::Signature < Base def initialize(registry) @registry = registry super(@registry, 'function signature') end def signature @registry[:signature] end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/helpers.rb000066400000000000000000000014031466634474300267030ustar00rootroot00000000000000# frozen_string_literal: true # Helpers for rendering Markdown module PuppetStrings::Markdown::Helpers # Formats code as either inline or a block. # # Note that this does not do any escaping even if the code contains ` or ```. # # @param [String] code The code to format. # @param [Symbol] type The type of the code, e.g. :text, :puppet, or :ruby. # @param [String] block_prefix String to insert before if it’s a block. # @param [String] inline_prefix String to insert before if it’s inline. # @returns [String] Markdown def code_maybe_block(code, type: :puppet, block_prefix: "\n\n", inline_prefix: ' ') if code.to_s.include?("\n") "#{block_prefix}```#{type}\n#{code}\n```" else "#{inline_prefix}`#{code}`" end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/puppet_class.rb000066400000000000000000000006161466634474300277500ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/markdown/base' module PuppetStrings::Markdown # Generates Markdown for a Puppet Class. class PuppetClass < Base group_name 'Classes' yard_types [:puppet_class] def initialize(registry) @template = 'classes_and_defines.erb' super(registry, 'class') end def render super(@template) end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/puppet_plan.rb000066400000000000000000000006101466634474300275670ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/markdown/base' module PuppetStrings::Markdown # Generates Markdown for a Puppet Plan. class PuppetPlan < Base group_name 'Plans' yard_types [:puppet_plan] def initialize(registry) @template = 'classes_and_defines.erb' super(registry, 'plan') end def render super(@template) end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/puppet_task.rb000066400000000000000000000010271466634474300276020ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/markdown/base' module PuppetStrings::Markdown # Generates Markdown for a Puppet Task. class PuppetTask < Base group_name 'Tasks' yard_types [:puppet_task] def initialize(registry) @template = 'puppet_task.erb' @registry = registry super(registry, 'task') end def render super(@template) end def supports_noop @registry[:supports_noop] end def input_method @registry[:input_method] end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/resource_type.rb000066400000000000000000000025061466634474300301360ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/markdown/base' module PuppetStrings::Markdown # Generates Markdown for a Puppet Resource Type. class ResourceType < Base group_name 'Resource types' yard_types [:puppet_type] def initialize(registry) @template = 'resource_type.erb' super(registry, 'type') end def render super(@template) end def properties return nil unless @registry[:properties] @registry[:properties].sort_by { |p| p[:name] } end def checks return nil unless @registry[:checks] @registry[:checks].sort_by { |p| p[:name] } end # "checks" (such as "onlyif" or "creates") are another type of property def properties_and_checks return nil if properties.nil? && checks.nil? ((properties || []) + (checks || [])).sort_by { |p| p[:name] }.map do |prop| prop[:link] = clean_link("$#{name}::#{prop[:name]}") prop end end def parameters return nil unless @registry[:parameters] @registry[:parameters].sort_by { |p| p[:name] }.map do |param| param[:link] = clean_link("$#{name}::#{param[:name]}") param end end def regex_in_data_type?(data_type) m = data_type.match(%r{\w+\[/.*/\]}) m unless m.nil? || m.to_a.empty? end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/templates/000077500000000000000000000000001466634474300267145ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/templates/classes_and_defines.erb000066400000000000000000000032761466634474300333720ustar00rootroot00000000000000### `<%= name %>` <% if text -%> <%= text %> <% elsif summary -%> <%= summary %> <% else -%> <%= "The #{name} class." %> <% end -%> <% if deprecated -%> * **DEPRECATED** <%= deprecated %> <% end -%> <% if todo -%> * **TODO** <%= todo %> <% end -%> <% if note -%> * **Note** <%= note %> <% end -%> <% if since -%> * **Since** <%= since %> <% end -%> <% if see -%> * **See also** <% see.each do |sa| -%> <% if sa[:name] -%> <%= " * #{sa[:name]}" %> <% end -%> <% if sa[:text] -%> <%= " * #{sa[:text]}" %> <% end -%> <% end -%> <% end -%> <% if examples -%> #### Examples <% examples.each do |eg| -%> ##### <%= eg[:name] %> ```puppet <%= eg[:text] %> ``` <% end -%> <% end -%> <% if params -%> #### Parameters The following parameters are available in the `<%= name %>` <%= @type %>: <% params.each do |param| -%> * [`<%= param[:name] %>`](#<%= param[:link] %>) <% end -%> <% params.each do |param| -%> ##### `<%= param[:name] %>` <% if param[:types] -%> Data type:<%= code_maybe_block(param[:types].join(', ')) %> <% end -%> <%= param[:text] %> <% if options_for_param(param[:name]) -%> Options: <% options_for_param(param[:name]).each do |o| -%> <% if o[:opt_types] -%> * **<%= o[:opt_name] %>** `<%= o[:opt_types][0] %>`: <%= o[:opt_text] %> <% else -%> * **<%= o[:opt_name] %>**: <%= o[:opt_text] %> <% end -%> <% end -%> <% end -%> <% if enums_for_param(param[:name]) -%> Options: <% enums_for_param(param[:name]).each do |e| -%> * **<%= e[:opt_name] %>**: <%= e[:opt_text] %> <% end -%> <% end -%> <% if defaults && defaults[param[:name]] -%> Default value:<%= code_maybe_block(defaults[param[:name]]) %> <% end -%> <% end -%> <% end -%> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/templates/data_type.erb000066400000000000000000000035411466634474300313630ustar00rootroot00000000000000### `<%= name %>` <% if text -%> <%= text %> <% elsif summary -%> <%= summary %> <% else -%> <%= "The #{name} data type." %> <% end -%> <% if deprecated -%> * **DEPRECATED** <%= deprecated %> <% end -%> <% if todo -%> * **TODO** <%= todo %> <% end -%> <% if note -%> * **Note** <%= note %> <% end -%> <% if since -%> * **Since** <%= since %> <% end -%> <% if see -%> * **See also** <% see.each do |sa| -%> <% if sa[:name] -%> <%= " * #{sa[:name]}" %> <% end -%> <% if sa[:text] -%> <%= " * #{sa[:text]}" %> <% end -%> <% end -%> <% end -%> <% if examples -%> #### Examples <% examples.each do |eg| -%> ##### <%= eg[:name] %> ```puppet <%= eg[:text] %> ``` <% end -%> <% end -%> <% if alias_of -%> Alias of<%= code_maybe_block(alias_of) %> <% end -%> <% if params -%> #### Parameters The following parameters are available in the `<%= name %>` <%= @type %>: <% params.each do |param| -%> * [`<%= param[:name] %>`](#<%= param[:link] %>) <% end -%> <% params.each do |param| -%> ##### `<%= param[:name] %>` <% if param[:types] -%> Data type:<%= code_maybe_block(param[:types].join(', ')) %> <% end -%> <%= param[:text] %> <% if options_for_param(param[:name]) -%> Options: <% options_for_param(param[:name]).each do |o| -%> * **<%= o[:opt_name] %>** `<%= o[:opt_types][0] %>`: <%= o[:opt_text] %> <% end -%> <% end -%> <% if enums_for_param(param[:name]) -%> Options: <% enums_for_param(param[:name]).each do |e| -%> * **<%= e[:opt_name] %>**: <%= e[:opt_text] %> <% end -%> <% end -%> <% if defaults && defaults[param[:name]] -%> Default value:<%= code_maybe_block(defaults[param[:name]]) %> <% end -%> <% end -%> <% end -%> <% if functions -%> #### Functions The following functions are available in the `<%= name %>` <%= @type %>. <% functions.each do |func| -%><%= func.render -%><% end -%> <% end -%> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/templates/data_type_function.erb000066400000000000000000000022161466634474300332660ustar00rootroot00000000000000### `<%= name %>` #### `<%= signature %>` <% if text -%> <%= text %> <% elsif summary -%> <%= summary %> <% else -%> <%= "The #{name} function." %> <% end -%> <% if note -%> * **Note** <%= note %> <% end -%> <% if return_type -%> Returns: `<%= return_type %>`<% if return_val %> <%= return_val %><% end %> <% end -%> <% if raises -%> Raises: <% raises.each do |r| -%> * <%= error_type(r[:text]) %> <%= error_text(r[:text]) %> <% end -%> <% end -%> <% if examples -%> ##### Examples <% examples.each do |eg| -%> ###### <%= eg[:name] %> ```puppet <%= eg[:text] %> ``` <% end -%> <% end -%> <% if params -%> <% params.each do |param| -%> ##### `<%= param[:name] %>` Data type:<%= code_maybe_block(param[:types][0]) %> <%= param[:text] %> <% if options_for_param(param[:name]) -%> Options: <% options_for_param(param[:name]).each do |o| -%> * **<%= o[:opt_name] %>** `<%= o[:opt_types][0] %>`: <%= o[:opt_text] %> <% end -%> <% end -%> <% if enums_for_param(param[:name]) -%> Options: <% enums_for_param(param[:name]).each do |e| -%> * **<%= e[:opt_name] %>**: <%= e[:opt_text] %> <% end -%> <% end -%> <% end -%> <% end -%> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/templates/function.erb000066400000000000000000000033061466634474300312350ustar00rootroot00000000000000### `<%= name %>` Type: <%= type %> <% if text -%> <%= text %> <% elsif summary -%> <%= summary %> <% else -%> <%= "The #{name} function." %> <% end -%> <% if deprecated -%> * **DEPRECATED** <%= deprecated %> <% end -%> <% if todo -%> * **TODO** <%= todo %> <% end -%> <% if note -%> * **Note** <%= note %> <% end -%> <% if examples -%> #### Examples <% examples.each do |eg| -%> ##### <%= eg[:name] %> ```puppet <%= eg[:text] %> ``` <% end -%> <% end -%> <% signatures.each do |sig| -%> #### `<%= sig.signature %>` <% if sig.text -%> <%= sig.text %> <% elsif sig.summary -%> <%= sig.summary %> <% else -%> <%= "The #{name} function." %> <% end -%> <% if sig.note -%> * **Note** <%= sig.note %> <% end -%> <% if sig.return_type -%> Returns: `<%= sig.return_type %>`<% if sig.return_val %> <%= sig.return_val %><% end %> <% end -%> <% if raises -%> Raises: <% raises.each do |r| -%> * <%= error_type(r[:text]) %> <%= error_text(r[:text]) %> <% end -%> <% end -%> <% if sig.examples -%> ##### Examples <% sig.examples.each do |eg| -%> ###### <%= eg[:name] %> ```puppet <%= eg[:text] %> ``` <% end -%> <% end -%> <% if sig.params -%> <% sig.params.each do |param| -%> ##### `<%= param[:name] %>` Data type:<%= code_maybe_block(param[:types][0]) %> <%= param[:text] %> <% if sig.options_for_param(param[:name]) -%> Options: <% sig.options_for_param(param[:name]).each do |o| -%> * **<%= o[:opt_name] %>** `<%= o[:opt_types][0] %>`: <%= o[:opt_text] %> <% end -%> <% end -%> <% if sig.enums_for_param(param[:name]) -%> Options: <% sig.enums_for_param(param[:name]).each do |e| -%> * **<%= e[:opt_name] %>**: <%= e[:opt_text] %> <% end -%> <% end -%> <% end -%> <% end -%> <% end -%> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/templates/puppet_task.erb000066400000000000000000000006621466634474300317510ustar00rootroot00000000000000### `<%= name %>` <% if text -%> <%= text %> <% elsif summary -%> <%= summary %> <% else -%> <%= "The #{name} task." %> <% end -%> **Supports noop?** <%= supports_noop %> <% if params -%> #### Parameters <% params.each do |param| -%> ##### `<%= param[:name] %>` <% if param[:types] -%> Data type:<%= code_maybe_block(param[:types].join(', ')) %> <% end -%> <%= param[:text] %> <% end -%> <% end -%> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/templates/resource_type.erb000066400000000000000000000063471466634474300323100ustar00rootroot00000000000000### `<%= name %>` <% if text -%> <%= text %> <% elsif summary -%> <%= summary %> <% else -%> <%= "The #{name} type." %> <% end -%> <% if deprecated -%> * **DEPRECATED** <%= deprecated %> <% end -%> <% if todo -%> * **TODO** <%= todo %> <% end -%> <% if note -%> * **Note** <%= note %> <% end -%> <% if since -%> * **Since** <%= since %> <% end -%> <% if see -%> * **See also** <% see.each do |sa| -%> <% if sa[:name] -%> <%= " * #{sa[:name]}" %> <% end -%> <% if sa[:text] -%> <%= " * #{sa[:text]}" %> <% end -%> <% end -%> <% end -%> <% if examples -%> #### Examples <% examples.each do |eg| -%> ##### <%= eg[:name] %> ```puppet <%= eg[:text] %> ``` <% end -%> <% end -%> <% if properties_and_checks -%> #### Properties The following properties are available in the `<%= name %>` <%= @type %>. <% properties_and_checks.each do |prop| -%> ##### `<%= prop[:name] %>` <% if prop[:values] -%> Valid values: `<%= prop[:values].join('`, `') %>` <% end -%> <% if prop[:isnamevar] -%> namevar <% end -%> <% if prop[:aliases] -%> Aliases: `<%= prop[:aliases].to_s.delete('{').delete('}') %>` <% end -%> <% if prop[:data_type] -%> Data type: `<%= prop[:data_type] %>`<%= "\n_\*this data type contains a regex that may not be accurately reflected in generated documentation_" if regex_in_data_type?(prop[:data_type]) %> <% end -%> <%= prop[:description] %> <% if options_for_param(prop[:name]) -%> Options: <% options_for_param(prop[:name]).each do |o| -%> * **<%= o[:opt_name] %>** `<%= o[:opt_types][0] %>`: <%= o[:opt_text] %> <% end -%> <% end -%> <% if enums_for_param(prop[:name]) -%> Options: <% enums_for_param(prop[:name]).each do |e| -%> * **<%= e[:opt_name] %>**: <%= e[:opt_text] %> <% end -%> <% end -%> <% if prop[:default] -%> Default value:<%= code_maybe_block(prop[:default], type: :ruby) %> <% end -%> <% end -%> <% end -%> <% if parameters -%> #### Parameters The following parameters are available in the `<%= name %>` <%= @type %>. <% parameters.each do |param| -%> * [`<%= param[:name] %>`](#<%= param[:link] %>) <% end -%> <% parameters.each do |param| -%> ##### `<%= param[:name] %>` <% if param[:values] -%> Valid values: `<%= param[:values].join('`, `') %>` <% end -%> <% if param[:isnamevar] -%> namevar <% end -%> <% if param[:aliases] -%> Aliases: `<%= param[:aliases].to_s.delete('{').delete('}') %>` <% end -%> <% if param[:data_type] -%> Data type: `<%= param[:data_type] %>`<%= "\n_\*this data type contains a regex that may not be accurately reflected in generated documentation_" if regex_in_data_type?(param[:data_type]) %> <% end -%> <% if param[:description] -%> <%= word_wrap(param[:description]) %> <% end -%> <% if options_for_param(param[:name]) -%> Options: <% options_for_param(param[:name]).each do |o| -%> * **<%= o[:opt_name] %>** `<%= o[:opt_types][0] %>`: <%= o[:opt_text] %> <% end -%> <% end -%> <% if enums_for_param(param[:name]) -%> Options: <% enums_for_param(param[:name]).each do |e| -%> * **<%= e[:opt_name] %>**: <%= e[:opt_text] %> <% end -%> <% end -%> <% if param[:default] -%> Default value: `<%= param[:default] %>` <% end -%> <% if param[:required_features] -%> Required features: <%= param[:required_features] %>. <% end -%> <% end -%> <% end -%> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/markdown/templates/table_of_contents.erb000066400000000000000000000012151466634474300330750ustar00rootroot00000000000000<% unless items.empty? -%> ### <%= group_name %> <% if has_public -%> <% if has_private # only display public heading if we have both -%> #### Public <%= group_name %> <% end -%> <% items.each do |item| -%> <% unless item[:private] -%> * [`<%= item[:name] %>`](#<%= item[:link] %>)<% unless item[:desc].nil? || item[:desc].empty? %>: <%= item[:desc] %><% end %> <% end -%> <% end -%> <% end -%> <% if has_private -%> #### Private <%= group_name %> <% items.each do |item| -%> <% if item[:private] -%> * `<%= item[:name] %>`<% unless item[:desc].nil? || item[:desc].empty? %>: <%= item[:desc] %><% end %> <% end -%> <% end -%> <% end -%> <% end -%> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/monkey_patches/000077500000000000000000000000001466634474300261055ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/monkey_patches/display_object_command.rb000066400000000000000000000007541466634474300331310ustar00rootroot00000000000000# frozen_string_literal: true # Monkey patch URL decoding in object displays. Usually :: is interpreted as a # namespace, but this is disabled in our base object, and so instead gets # URL-encoded. require 'yard/server/commands/display_object_command' # Monkey patch YARD::Server::Commands::DisplayObjectCommand object_path. class YARD::Server::Commands::DisplayObjectCommand private alias object_path_yard object_path def object_path object_path_yard.gsub('_3A', ':') end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/tasks.rb000066400000000000000000000005141466634474300245460ustar00rootroot00000000000000# frozen_string_literal: true require 'rake' require 'rake/tasklib' # Ensure PuppetStrings is loaded. module PuppetStrings end # The module for Puppet Strings rake tasks. module PuppetStrings::Tasks require 'puppet-strings/tasks/generate' require 'puppet-strings/tasks/gh_pages' require 'puppet-strings/tasks/validate' end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/tasks/000077500000000000000000000000001466634474300242215ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/tasks/generate.rb000066400000000000000000000041521466634474300263420ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings' # Implements the strings:generate task. namespace :strings do desc 'Generate Puppet documentation with YARD.' task :generate, [:patterns, :debug, :backtrace, :markup, :json, :markdown, :yard_args] do |_t, args| patterns = args[:patterns] patterns = patterns.split if patterns patterns ||= PuppetStrings::DEFAULT_SEARCH_PATTERNS options = { debug: args[:debug] == 'true', backtrace: args[:backtrace] == 'true', markup: args[:markup] || 'markdown' } raise('Error: Both JSON and Markdown output have been selected. Please select one.') if args[:json] == 'true' && args[:markdown] == 'true' # rubocop:disable Style/PreferredHashMethods # Because of Ruby, true and false from the args are both strings and both true. Here, # when the arg is set to false (or empty), set it to real false, else real true. Then, # if the arg is set simply to 'true', assume default behavior is expected and set the path # to nil to elicit that, else set to the path given. # @param [Hash] args from the Rake task cli # @param [Hash] options to send to the generate function # @param [Symbol] possible format option # @return nil def parse_format_option(args, options, format) return unless args.has_key? format options[format] = !(args[format] == 'false' || args[format].empty?) return unless options[format] options[:path] = args[format] == 'true' ? nil : args[format] end # rubocop:enable Style/PreferredHashMethods %i[json markdown].each { |format| parse_format_option(args, options, format) } warn('yard_args behavior is a little dodgy, use at your own risk') if args[:yard_args] options[:yard_args] = args[:yard_args].split if args.key? :yard_args PuppetStrings.generate(patterns, options) end namespace :generate do desc 'Generate Puppet Reference documentation.' task :reference, [:patterns, :debug, :backtrace] do |_t, args| Rake::Task['strings:generate'].invoke(args[:patterns], args[:debug], args[:backtrace], nil, 'false', 'true') end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/tasks/gh_pages.rb000066400000000000000000000033361466634474300263300ustar00rootroot00000000000000# frozen_string_literal: true require 'English' require 'puppet-strings/tasks' namespace :strings do namespace :gh_pages do task :checkout do if Dir.exist?('doc') raise "The 'doc' directory (#{File.expand_path('doc')}) is not a Git repository! Remove it and run the Rake task again." unless Dir.exist?('doc/.git') Dir.chdir('doc') do system 'git checkout gh-pages' system 'git pull --rebase origin gh-pages' end else git_uri = `git config --get remote.origin.url`.strip raise "Could not determine the remote URL for origin: ensure the current directory is a Git repro with a remote named 'origin'." unless $CHILD_STATUS.success? Dir.mkdir('doc') Dir.chdir('doc') do system 'git init' system "git remote add origin #{git_uri}" system 'git pull origin gh-pages' system 'git checkout -b gh-pages' end end end task :configure do unless File.exist?(File.join('doc', '_config.yml')) Dir.chdir('doc') do File.write('_config.yml', 'include: _index.html') end end end task :push do output = `git describe --long 2>/dev/null` # If a project has never been tagged, fall back to latest SHA git_sha = output.empty? ? `git log --pretty=format:'%H' -n 1` : output Dir.chdir('doc') do system 'git add .' system "git commit -m '[strings] Generated Documentation Update at Revision #{git_sha}'" system 'git push origin gh-pages -f' end end desc 'Update docs on the gh-pages branch and push to GitHub.' task update: %i[ checkout strings:generate configure push ] end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/tasks/validate.rb000066400000000000000000000020131466634474300263330ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings' require 'tempfile' namespace :strings do namespace :validate do desc 'Validate the reference is up to date' task :reference, [:patterns, :debug, :backtrace] do |_t, args| filename = 'REFERENCE.md' unless File.exist?(filename) warn "#{filename} does not exist" exit 1 end patterns = args[:patterns] patterns = patterns.split if patterns patterns ||= PuppetStrings::DEFAULT_SEARCH_PATTERNS generated = Tempfile.create do |file| options = { debug: args[:debug] == 'true', backtrace: args[:backtrace] == 'true', json: false, markdown: true, path: file } PuppetStrings.generate(patterns, options) file.read end existing = File.read(filename) if generated != existing warn "#{filename} is outdated; to regenerate: bundle exec rake strings:generate:reference" exit 1 end end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/version.rb000066400000000000000000000001141466634474300251020ustar00rootroot00000000000000# frozen_string_literal: true module PuppetStrings VERSION = '4.1.3' end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard.rb000066400000000000000000000101761466634474300243650ustar00rootroot00000000000000# frozen_string_literal: true require 'yard' # Module for YARD related functionality. module PuppetStrings::Yard require 'puppet-strings/yard/code_objects' require 'puppet-strings/yard/handlers' require 'puppet-strings/yard/tags' require 'puppet-strings/yard/parsers' require 'puppet-strings/monkey_patches/display_object_command' # Sets up YARD for use with puppet-strings. # @return [void] def self.setup! # Register our factory YARD::Tags::Library.default_factory = PuppetStrings::Yard::Tags::Factory # Register the template path YARD::Templates::Engine.register_template_path(File.join(File.dirname(__FILE__), 'yard', 'templates')) # Register the Puppet parser YARD::Parser::SourceParser.register_parser_type(:puppet, PuppetStrings::Yard::Parsers::Puppet::Parser, ['pp']) YARD::Parser::SourceParser.register_parser_type(:json, PuppetStrings::Yard::Parsers::JSON::Parser, ['json']) # Register our handlers YARD::Handlers::Processor.register_handler_namespace(:puppet, PuppetStrings::Yard::Handlers::Puppet) YARD::Handlers::Processor.register_handler_namespace(:puppet_ruby, PuppetStrings::Yard::Handlers::Ruby) YARD::Handlers::Processor.register_handler_namespace(:json, PuppetStrings::Yard::Handlers::JSON) # Register the tag directives PuppetStrings::Yard::Tags::ParameterDirective.register! PuppetStrings::Yard::Tags::PropertyDirective.register! # Register the summary tag PuppetStrings::Yard::Tags::SummaryTag.register! # Register the enum tag PuppetStrings::Yard::Tags::EnumTag.register! # Ignore documentation on Puppet DSL calls # This prevents the YARD DSL parser from emitting warnings for Puppet's Ruby DSL YARD::Handlers::Ruby::DSLHandlerMethods::IGNORE_METHODS['create_function'] = true YARD::Handlers::Ruby::DSLHandlerMethods::IGNORE_METHODS['newtype'] = true end end # Monkey patch YARD::CLI::Yardoc#all_objects to return our custom code objects. # @private class YARD::CLI::Yardoc def all_objects YARD::Registry.all( :root, :module, :class, :puppet_class, :puppet_data_type, :puppet_data_type_alias, :puppet_defined_type, :puppet_type, :puppet_provider, :puppet_function, :puppet_task, :puppet_plan ) end end # Monkey patch the stats object to return statistics for our objects. # This is the recommended way to add custom stats. # @private class YARD::CLI::Stats def stats_for_puppet_classes output 'Puppet Classes', *type_statistics_all(:puppet_class) end def stats_for_puppet_data_types output 'Puppet Data Types', *type_statistics_all(:puppet_data_type) end def stats_for_puppet_data_type_aliases output 'Puppet Data Type Aliases', *type_statistics_all(:puppet_data_type_alias) end def stats_for_puppet_defined_types output 'Puppet Defined Types', *type_statistics_all(:puppet_defined_type) end def stats_for_puppet_types output 'Puppet Types', *type_statistics_all(:puppet_type) end def stats_for_puppet_providers output 'Puppet Providers', *type_statistics_all(:puppet_provider) end def stats_for_puppet_functions output 'Puppet Functions', *type_statistics_all(:puppet_function) end def stats_for_puppet_tasks output 'Puppet Tasks', *type_statistics_all(:puppet_task) end def stats_for_puppet_plans return unless PuppetStrings.puppet_5? output 'Puppet Plans', *type_statistics_all(:puppet_plan) end def output(name, data, undoc = nil) # Monkey patch output to accommodate our larger header widths @total += data if data.is_a?(Integer) && undoc @undocumented += undoc if undoc.is_a?(Integer) data = if undoc "#{data} (#{undoc} undocumented)" else data.to_s end log.puts("#{name.ljust(25)} #{data}") end # This differs from the YARD implementation in that it considers # a docstring without text but with tags to be undocumented. def type_statistics_all(type) objs = all_objects.select { |m| m.type == type } undoc = objs.select { |m| m.docstring.all.empty? } @undoc_list |= undoc if @undoc_list [objs.size, undoc.size] end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/000077500000000000000000000000001466634474300240335ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/code_objects.rb000066400000000000000000000011311466634474300267770ustar00rootroot00000000000000# frozen_string_literal: true # The module for custom YARD code objects. module PuppetStrings::Yard::CodeObjects require 'puppet-strings/yard/code_objects/class' require 'puppet-strings/yard/code_objects/data_type' require 'puppet-strings/yard/code_objects/data_type_alias' require 'puppet-strings/yard/code_objects/defined_type' require 'puppet-strings/yard/code_objects/type' require 'puppet-strings/yard/code_objects/provider' require 'puppet-strings/yard/code_objects/function' require 'puppet-strings/yard/code_objects/task' require 'puppet-strings/yard/code_objects/plan' end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/code_objects/000077500000000000000000000000001466634474300264565ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/code_objects/base.rb000066400000000000000000000012401466634474300277120ustar00rootroot00000000000000# frozen_string_literal: true # Implements the base code object. class PuppetStrings::Yard::CodeObjects::Base < YARD::CodeObjects::NamespaceObject # Allocates a new code object. # @param [Array] args The arguments to initialize the code object with. # @return Returns the code object. def self.new(*args) # Skip the super class' implementation because it detects :: in names and this will cause namespaces in the output we don't want object = Object.class.instance_method(:new).bind_call(self, *args) existing = YARD::Registry.at(object.path) object = existing if existing.instance_of?(self) yield(object) if block_given? object end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/code_objects/class.rb000066400000000000000000000037271466634474300301210ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/code_objects/group' # Implements the group for Puppet classes. class PuppetStrings::Yard::CodeObjects::Classes < PuppetStrings::Yard::CodeObjects::Group # Gets the singleton instance of the group. # @return Returns the singleton instance of the group. def self.instance super(:puppet_classes) end # Gets the display name of the group. # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces. # @return [String] Returns the display name of the group. def name(_prefix = false) 'Puppet Classes' end end # Implements the Puppet class code object. class PuppetStrings::Yard::CodeObjects::Class < PuppetStrings::Yard::CodeObjects::Base attr_reader :statement, :parameters # Initializes a Puppet class code object. # @param [PuppetStrings::Parsers::ClassStatement] statement The class statement that was parsed. # @return [void] def initialize(statement) @statement = statement @parameters = statement.parameters.map { |p| [p.name, p.value] } super(PuppetStrings::Yard::CodeObjects::Classes.instance, statement.name) end # Gets the type of the code object. # @return Returns the type of the code object. def type :puppet_class end # Gets the source of the code object. # @return Returns the source of the code object. def source @statement.source end # Converts the code object to a hash representation. # @return [Hash] Returns a hash representation of the code object. def to_hash hash = {} hash[:name] = name hash[:file] = file hash[:line] = line hash[:inherits] = statement.parent_class if statement.parent_class hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring) defaults = Hash[*parameters.reject { |p| p[1].nil? }.flatten] hash[:defaults] = defaults unless defaults.nil? || defaults.empty? hash[:source] = source unless source.nil? || source.empty? hash end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/code_objects/data_type.rb000066400000000000000000000060351466634474300307610ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/code_objects/group' require 'puppet-strings/yard/util' # Implements the group for Puppet DataTypes. class PuppetStrings::Yard::CodeObjects::DataTypes < PuppetStrings::Yard::CodeObjects::Group # Gets the singleton instance of the group. # @return Returns the singleton instance of the group. def self.instance super(:puppet_data_types) end # Gets the display name of the group. # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces. # @return [String] Returns the display name of the group. def name(_prefix = false) 'Puppet Data Types' end end # Implements the Puppet DataType code object. class PuppetStrings::Yard::CodeObjects::DataType < PuppetStrings::Yard::CodeObjects::Base # Initializes a Puppet class code object. # @param [String] The name of the Data Type # @return [void] def initialize(name) super(PuppetStrings::Yard::CodeObjects::DataTypes.instance, name) @defaults = {} end # Gets the type of the code object. # @return Returns the type of the code object. def type :puppet_data_type end # Gets the source of the code object. # @return Returns the source of the code object. def source # Not implemented, but would be nice! nil end def add_parameter(name, type, default) tag = docstring.tags(:param).find { |item| item.name == name } if tag.nil? tag = YARD::Tags::Tag.new(:param, '', nil, name) docstring.add_tag(tag) end type = [type] unless type.is_a?(Array) tag.types = type if tag.types.nil? set_parameter_default(name, default) end def set_parameter_default(param_name, default) defaults.delete(param_name) defaults[param_name] = default unless default.nil? end def parameters docstring.tags(:param).map { |tag| [tag.name, defaults[tag.name]] } end def add_function(name, return_type, parameter_types) meth_obj = YARD::CodeObjects::MethodObject.new(self, name, :class) # Add return tag meth_obj.add_tag(YARD::Tags::Tag.new(:return, '', return_type)) # Add parameters parameter_types.each_with_index do |param_type, index| meth_obj.add_tag(YARD::Tags::Tag.new(:param, '', [param_type], "param#{index + 1}")) end meths << meth_obj end def functions meths end # Converts the code object to a hash representation. # @return [Hash] Returns a hash representation of the code object. def to_hash hash = {} hash[:name] = name hash[:file] = file hash[:line] = line hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring, %i[param option enum return example]) hash[:defaults] = defaults unless defaults.nil? || defaults.empty? hash[:source] = source unless source.nil? || source.empty? hash[:functions] = functions.map do |func| { name: func.name, signature: func.signature, docstring: PuppetStrings::Yard::Util.docstring_to_hash(func.docstring, %i[param option enum return example]) } end hash end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/code_objects/data_type_alias.rb000066400000000000000000000035631466634474300321350ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/code_objects/group' require 'puppet-strings/yard/util' # Implements the group for Puppet DataTypeAliases. class PuppetStrings::Yard::CodeObjects::DataTypeAliases < PuppetStrings::Yard::CodeObjects::Group # Gets the singleton instance of the group. # @return Returns the singleton instance of the group. def self.instance super(:puppet_data_type_aliases) end # Gets the display name of the group. # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces. # @return [String] Returns the display name of the group. def name(_prefix = false) 'Puppet Data Type Aliases' end end # Implements the Puppet DataTypeAlias code object. class PuppetStrings::Yard::CodeObjects::DataTypeAlias < PuppetStrings::Yard::CodeObjects::Base attr_reader :statement attr_accessor :alias_of # Initializes a Puppet data type alias code object. # @param [PuppetStrings::Parsers::DataTypeAliasStatement] statement The data type alias statement that was parsed. # @return [void] def initialize(statement) @statement = statement @alias_of = statement.alias_of super(PuppetStrings::Yard::CodeObjects::DataTypeAliases.instance, statement.name) end # Gets the type of the code object. # @return Returns the type of the code object. def type :puppet_data_type_alias end # Gets the source of the code object. # @return Returns the source of the code object. def source # Not implemented, but would be nice! nil end # Converts the code object to a hash representation. # @return [Hash] Returns a hash representation of the code object. def to_hash hash = {} hash[:name] = name hash[:file] = file hash[:line] = line hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring) hash[:alias_of] = alias_of hash end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/code_objects/defined_type.rb000066400000000000000000000037151466634474300314500ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/code_objects/group' # Implements the group for Puppet defined types. class PuppetStrings::Yard::CodeObjects::DefinedTypes < PuppetStrings::Yard::CodeObjects::Group # Gets the singleton instance of the group. # @return Returns the singleton instance of the group. def self.instance super(:puppet_defined_types) end # Gets the display name of the group. # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces. # @return [String] Returns the display name of the group. def name(_prefix = false) 'Defined Types' end end # Implements the Puppet defined type code object. class PuppetStrings::Yard::CodeObjects::DefinedType < PuppetStrings::Yard::CodeObjects::Base attr_reader :statement, :parameters # Initializes a Puppet defined type code object. # @param [PuppetStrings::Parsers::DefinedTypeStatement] statement The defined type statement that was parsed. # @return [void] def initialize(statement) @statement = statement @parameters = statement.parameters.map { |p| [p.name, p.value] } super(PuppetStrings::Yard::CodeObjects::DefinedTypes.instance, statement.name) end # Gets the type of the code object. # @return Returns the type of the code object. def type :puppet_defined_type end # Gets the source of the code object. # @return Returns the source of the code object. def source @statement.source end # Converts the code object to a hash representation. # @return [Hash] Returns a hash representation of the code object. def to_hash hash = {} hash[:name] = name hash[:file] = file hash[:line] = line hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring) defaults = Hash[*parameters.reject { |p| p[1].nil? }.flatten] hash[:defaults] = defaults unless defaults.nil? || defaults.empty? hash[:source] = source unless source.nil? || source.empty? hash end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/code_objects/function.rb000066400000000000000000000067121466634474300306360ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/code_objects/group' # Implements the group for Puppet functions. class PuppetStrings::Yard::CodeObjects::Functions < PuppetStrings::Yard::CodeObjects::Group # Gets the singleton instance of the group. # @param [Symbol] type The function type to get the group for. # @return Returns the singleton instance of the group. def self.instance(type) super(:"puppet_functions_#{type}") end # Gets the display name of the group. # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces. # @return [String] Returns the display name of the group. def name(_prefix = false) 'Puppet Functions' end end # Implements the Puppet function code object. class PuppetStrings::Yard::CodeObjects::Function < PuppetStrings::Yard::CodeObjects::Base # Identifier for 3.x Ruby API functions RUBY_3X = :ruby3x # Identifier for 4.x Ruby API functions RUBY_4X = :ruby4x # Identifier for Puppet language functions PUPPET = :puppet attr_accessor :parameters # Initializes a Puppet function code object. # @param [String] name The name of the function. # @param [Symbol] function_type The type of function (e.g. :ruby3x, :ruby4x, :puppet) # @return [void] def initialize(name, function_type) super(PuppetStrings::Yard::CodeObjects::Functions.instance(function_type), name) @parameters = [] @function_type = function_type end # Gets the type of the code object. # @return Returns the type of the code object. def type :puppet_function end # Gets the function type display string. # @return Returns the function type display string. def function_type case @function_type when RUBY_3X 'Ruby 3.x API' when RUBY_4X 'Ruby 4.x API' else 'Puppet Language' end end # Gets the Puppet signature of the function (single overload only). # @return [String] Returns the Puppet signature of the function. def signature return '' if has_tag? :overload tags = self.tags(:param) args = @parameters.map do |parameter| name, default = parameter tag = tags.find { |t| t.name == name } if tags type = tag&.types ? "#{tag.type} " : 'Any ' prefix = (name[0]).to_s if name.start_with?('*', '&') name = name[1..] if prefix default = " = #{default}" if default "#{type}#{prefix}$#{name}#{default}" end.join(', ') "#{@name}(#{args})" end # Converts the code object to a hash representation. # @return [Hash] Returns a hash representation of the code object. def to_hash hash = {} hash[:name] = name hash[:file] = file hash[:line] = line hash[:type] = @function_type.to_s hash[:signatures] = [] if has_tag? :overload # loop over overloads and append onto the signatures array tags(:overload).each do |o| hash[:signatures] << { signature: o.signature, docstring: PuppetStrings::Yard::Util.docstring_to_hash(o.docstring, %i[param option enum return example]) } end else hash[:signatures] << { signature: signature, docstring: PuppetStrings::Yard::Util.docstring_to_hash(docstring, %i[param option enum return example]) } end hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring) defaults = Hash[*parameters.reject { |p| p[1].nil? }.flatten] hash[:defaults] = defaults unless defaults.nil? || defaults.empty? hash[:source] = source unless source.nil? || source.empty? hash end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/code_objects/group.rb000066400000000000000000000016521466634474300301430ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/code_objects/base' # Implements the base class for "groups". # # A group behaves like a YARD namespace object, but displays differently in the HTML output. class PuppetStrings::Yard::CodeObjects::Group < PuppetStrings::Yard::CodeObjects::Base # Gets the singleton instance of the group. # @param [Symbol] key The key to lookup the group for. # @return Returns the singleton instance of the group. def self.instance(key) instance = P(:root, key) return instance unless instance.is_a?(YARD::CodeObjects::Proxy) instance = new(:root, key) instance.visibility = :hidden P(:root).children << instance instance end # Gets the path to the group. # @return [String] Returns the path to the group. def path @name.to_s end # Gets the type of the group. # @return [Symbol] Returns the type of the group. def type @name end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/code_objects/plan.rb000066400000000000000000000036001466634474300277340ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/code_objects/group' # Implements the group for Puppet plans. class PuppetStrings::Yard::CodeObjects::Plans < PuppetStrings::Yard::CodeObjects::Group # Gets the singleton instance of the group. # @return Returns the singleton instance of the group. def self.instance super(:puppet_plans) end # Gets the display name of the group. # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces. # @return [String] Returns the display name of the group. def name(_prefix = false) 'Puppet Plans' end end # Implements the Puppet plan code object. class PuppetStrings::Yard::CodeObjects::Plan < PuppetStrings::Yard::CodeObjects::Base attr_reader :statement, :parameters # Initializes a Puppet plan code object. # @param [PuppetStrings::Parsers::PlanStatement] statement The plan statement that was parsed. # @return [void] def initialize(statement) @statement = statement @parameters = statement.parameters.map { |p| [p.name, p.value] } super(PuppetStrings::Yard::CodeObjects::Plans.instance, statement.name) end # Gets the type of the code object. # @return Returns the type of the code object. def type :puppet_plan end # Gets the source of the code object. # @return Returns the source of the code object. def source @statement.source end # Converts the code object to a hash representation. # @return [Hash] Returns a hash representation of the code object. def to_hash hash = {} hash[:name] = name hash[:file] = file hash[:line] = line hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring) defaults = Hash[*parameters.reject { |p| p[1].nil? }.flatten] hash[:defaults] = defaults unless defaults.nil? || defaults.empty? hash[:source] = source unless source.nil? || source.empty? hash end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/code_objects/provider.rb000066400000000000000000000056461466634474300306500ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/code_objects/group' # Implements the group for Puppet providers. class PuppetStrings::Yard::CodeObjects::Providers < PuppetStrings::Yard::CodeObjects::Group # Gets the singleton instance of the group. # @param [String] type The resource type name for the provider. # @return Returns the singleton instance of the group. def self.instance(type) super(:"puppet_providers_#{type}") end # Gets the display name of the group. # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces. # @return [String] Returns the display name of the group. def name(_prefix = false) 'Providers' end end # Implements the Puppet provider code object. class PuppetStrings::Yard::CodeObjects::Provider < PuppetStrings::Yard::CodeObjects::Base attr_reader :type_name, :confines, :features, :defaults, :commands # Initializes a Puppet provider code object. # @param [String] type_name The resource type name for the provider. # @param [String] name The name of the provider.s # @return [void] def initialize(type_name, name) @type_name = type_name super(PuppetStrings::Yard::CodeObjects::Providers.instance(type_name), name) end # Gets the type of the code object. # @return Returns the type of the code object. def type :puppet_provider end # Adds a confine to the provider. # @param [String] key The confine's key. # @param [String] value The confine's value. # @return [void] def add_confine(key, value) return unless key && value @confines ||= {} @confines[key] = value end # Adds a feature to the provider. # @param [String] feature The feature to add to the provider. # @return [void] def add_feature(feature) return unless feature @features ||= [] @features << feature end # Adds a default to the provider. # @param [Array] constraints List of related key-pair values for the default. # @return [void] def add_default(constraints) return unless constraints @defaults ||= [] @defaults << constraints end # Adds a command to the provider. # @param [String] key The command's key. # @param [String] value The command's value. # @return [void] def add_command(key, value) return unless key && value @commands ||= {} @commands[key] = value end # Converts the code object to a hash representation. # @return [Hash] Returns a hash representation of the code object. def to_hash hash = {} hash[:name] = name hash[:type_name] = type_name hash[:file] = file hash[:line] = line hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring) hash[:confines] = confines if confines && !confines.empty? hash[:features] = features if features && !features.empty? hash[:defaults] = defaults if defaults && !defaults.empty? hash[:commands] = commands if commands && !commands.empty? hash end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/code_objects/task.rb000066400000000000000000000036421466634474300277520ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/code_objects/group' # Implements the group for Puppet tasks. class PuppetStrings::Yard::CodeObjects::Tasks < PuppetStrings::Yard::CodeObjects::Group # Gets the singleton instance of the group. # @return Returns the singleton instance of the group. def self.instance super(:puppet_tasks) end # Gets the display name of the group. # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces. # @return [String] Returns the display name of the group. def name(_prefix = false) 'Puppet Tasks' end end # Implements the Puppet task code object. class PuppetStrings::Yard::CodeObjects::Task < PuppetStrings::Yard::CodeObjects::Base attr_reader :statement # Initializes a JSON task code object. # @param statement TaskStatement object # @return [void] def initialize(statement) @name = statement.name @statement = statement super(PuppetStrings::Yard::CodeObjects::Tasks.instance, name) end # Gets the type of the code object. # @return Returns the type of the code object. def type :puppet_task end # Gets the source of the code object. # @return Returns the source of the code object. def source @statement.source end def parameters statement.parameters.map do |name, props| { name: name.to_s, tag_name: 'param', text: props['description'] || '', types: [props['type']] || '' } end end # Converts the code object to a hash representation. # @return [Hash] Returns a hash representation of the code object. def to_hash { name: name.to_s, file: statement.file, line: statement.line, docstring: { text: statement.docstring, tags: parameters }, source: statement.source, supports_noop: statement.json['supports_noop'] || false, input_method: statement.json['input_method'] } end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/code_objects/type.rb000066400000000000000000000142121466634474300277640ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/code_objects/group' require 'puppet-strings/yard/util' # Implements the group for Puppet resource types. class PuppetStrings::Yard::CodeObjects::Types < PuppetStrings::Yard::CodeObjects::Group # Gets the singleton instance of the group. # @return Returns the singleton instance of the group. def self.instance super(:puppet_types) end # Gets the display name of the group. # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces. # @return [String] Returns the display name of the group. def name(_prefix = false) 'Resource Types' end end # Implements the Puppet resource type code object. class PuppetStrings::Yard::CodeObjects::Type < PuppetStrings::Yard::CodeObjects::Base # Represents a resource type parameter. class Parameter attr_reader :name, :values, :aliases attr_accessor :docstring, :isnamevar, :default, :data_type, :required_features # Initializes a resource type parameter or property. # @param [String] name The name of the parameter or property. # @param [String] docstring The docstring for the parameter or property.s def initialize(name, docstring = nil) @name = name @docstring = docstring || '' @values = [] @data_type = [] @aliases = {} @isnamevar = false @default = nil end # Adds a value to the parameter or property. # @param [String] value The value to add. # @return [void] def add(value) @values << value end # Aliases a value to another value. # @param [String] new The new (alias) value. # @param [String] old The old (existing) value. # @return [void] def alias(new, old) @values << new unless @values.include? new @aliases[new] = old end # Converts the parameter to a hash representation. # @return [Hash] Returns a hash representation of the parameter. def to_hash hash = {} hash[:name] = name hash[:description] = docstring unless docstring.empty? hash[:values] = values unless values.empty? hash[:data_type] = data_type unless data_type.empty? hash[:aliases] = aliases unless aliases.empty? hash[:isnamevar] = true if isnamevar hash[:required_features] = required_features if required_features hash[:default] = default if default hash end end # Represents a resource type property (same attributes as a parameter). class Property < Parameter end class Check < Parameter end # Represents a resource type feature. class Feature attr_reader :name, :docstring # Initializes a new feature. # @param [String] name The name of the feature. # @param [String] docstring The docstring of the feature. def initialize(name, docstring) @name = name @docstring = PuppetStrings::Yard::Util.scrub_string(docstring).tr("\n", ' ') end # Converts the feature to a hash representation. # @return [Hash] Returns a hash representation of the feature. def to_hash hash = {} hash[:name] = name hash[:description] = docstring unless docstring.empty? hash end end attr_reader :properties, :features, :checks # Initializes a new resource type. # @param [String] name The resource type name. # @return [void] def initialize(name) super(PuppetStrings::Yard::CodeObjects::Types.instance, name) end # Gets the type of the code object. # @return Returns the type of the code object. def type :puppet_type end # Adds a parameter to the resource type # @param [PuppetStrings::Yard::CodeObjects::Type::Parameter] parameter The parameter to add. # @return [void] def add_parameter(parameter) @parameters ||= [] @parameters << parameter end # Adds a property to the resource type # @param [PuppetStrings::Yard::CodeObjects::Type::Property] property The property to add. # @return [void] def add_property(property) @properties ||= [] @properties << property end # Adds a feature to the resource type. # @param [PuppetStrings::Yard::CodeObjects::Type::Feature] feature The feature to add. # @return [void] def add_feature(feature) @features ||= [] @features << feature end # Adds a check to the resource type. # @param [PuppetStrings::Yard::CodeObjects::Type::Check] check The check to add. # @return [void] def add_check(check) @checks ||= [] @checks << check end def parameters @parameters ||= [] # guard against not filled parameters # just return params if there are no providers return @parameters if providers.empty? # return existing params if we have already added provider return @parameters if @parameters&.any? { |p| p.name == 'provider' } provider_param = Parameter.new( 'provider', "The specific backend to use for this `#{name}` resource. You will seldom need " \ 'to specify this --- Puppet will usually discover the appropriate provider for your platform.' ) @parameters ||= [] @parameters << provider_param end # Not sure if this is where this belongs or if providers should only be resolved at # render-time. For now, this should re-resolve on every call. # may be able to memoize this def providers providers = YARD::Registry.all(:"puppet_providers_#{name}") return providers if providers.empty? providers.first.children end # Converts the code object to a hash representation. # @return [Hash] Returns a hash representation of the code object. def to_hash hash = {} hash[:name] = name hash[:file] = file hash[:line] = line hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring) hash[:properties] = properties.sort_by(&:name).map(&:to_hash) if properties && !properties.empty? hash[:parameters] = parameters.sort_by(&:name).map(&:to_hash) if parameters && !parameters.empty? hash[:checks] = checks.sort_by(&:name).map(&:to_hash) if checks && !checks.empty? hash[:features] = features.sort_by(&:name).map(&:to_hash) if features && !features.empty? hash[:providers] = providers.sort_by(&:name).map(&:to_hash) if providers && !providers.empty? hash end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers.rb000066400000000000000000000021161466634474300261600ustar00rootroot00000000000000# frozen_string_literal: true # The module for custom YARD handlers. module PuppetStrings::Yard::Handlers # The module for custom Ruby YARD handlers. module Ruby require 'puppet-strings/yard/handlers/ruby/data_type_handler' require 'puppet-strings/yard/handlers/ruby/type_handler' require 'puppet-strings/yard/handlers/ruby/type_extras_handler' require 'puppet-strings/yard/handlers/ruby/rsapi_handler' require 'puppet-strings/yard/handlers/ruby/provider_handler' require 'puppet-strings/yard/handlers/ruby/function_handler' end # The module for custom JSON YARD handlers. module JSON require 'puppet-strings/yard/handlers/json/task_handler' end # The module for custom Puppet YARD handlers. module Puppet require 'puppet-strings/yard/handlers/puppet/class_handler' require 'puppet-strings/yard/handlers/puppet/data_type_alias_handler' require 'puppet-strings/yard/handlers/puppet/defined_type_handler' require 'puppet-strings/yard/handlers/puppet/function_handler' require 'puppet-strings/yard/handlers/puppet/plan_handler' end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/000077500000000000000000000000001466634474300256335ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/helpers.rb000066400000000000000000000006541466634474300276270ustar00rootroot00000000000000# frozen_string_literal: true # Implements a helper that logs a warning if a summary tag has more than 140 characters module PuppetStrings::Yard::Handlers::Helpers def self.validate_summary_tag(object) return unless object.has_tag?(:summary) && object.tag(:summary).text.length > 140 log.warn "The length of the summary for #{object.type} '#{object.name}' exceeds the recommended limit of 140 characters." end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/json/000077500000000000000000000000001466634474300266045ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/json/base.rb000066400000000000000000000003731466634474300300460ustar00rootroot00000000000000# frozen_string_literal: true # Implements the base class for all JSON handlers. class PuppetStrings::Yard::Handlers::JSON::Base < YARD::Handlers::Base def self.handles?(statement) handlers.any? { |handler| statement.is_a?(handler) } end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/json/task_handler.rb000066400000000000000000000017021466634474300315700ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/handlers/json/base' require 'puppet-strings/yard/parsers' require 'puppet-strings/yard/parsers/json/parser' # Implements the handler for JSON task metadata. class PuppetStrings::Yard::Handlers::JSON::TaskHandler < PuppetStrings::Yard::Handlers::JSON::Base handles PuppetStrings::Yard::Parsers::JSON::TaskStatement namespace_only process do object = PuppetStrings::Yard::CodeObjects::Task.new(statement) register object @kind = "Puppet Task #{object.name}." @statement = statement validate_description validate_params end def validate_description log.warn "Missing a description for #{@kind}." if @statement.docstring.empty? end def validate_params return if @statement.parameters.empty? @statement.parameters.each do |param, val| log.warn "Missing description for param '#{param}' in #{@kind}" if val['description'].nil? end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/puppet/000077500000000000000000000000001466634474300271505ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/puppet/base.rb000066400000000000000000000041241466634474300304100ustar00rootroot00000000000000# frozen_string_literal: true # Implements the base handler for Puppet language handlers. class PuppetStrings::Yard::Handlers::Puppet::Base < YARD::Handlers::Base # Determine sif the handler handles the given statement. # @param statement The statement that was parsed. # @return [Boolean] Returns true if the statement is handled by this handler or false if not. def self.handles?(statement) handlers.any? { |handler| statement.is_a?(handler) } end protected # Sets the parameter tag types for the given code object. # This also performs some validation on the parameter tags. # @param object The code object to set the parameter tag types for. # @return [void] def set_parameter_types(object) # Ensure there is an actual parameter for each parameter tag tags = object.tags(:param) tags.each do |tag| next if statement.parameters.find { |p| tag.name == p.name } log.warn "The @param tag for parameter '#{tag.name}' has no matching parameter at #{statement.file}:#{statement.line}." unless tag.name == 'name' || tag.name == 'title' end # Assign the types for the parameter statement.parameters.each do |parameter| tag = tags.find { |t| t.name == parameter.name } unless tag log.warn "Missing @param tag for parameter '#{parameter.name}' near #{statement.file}:#{statement.line}." unless object.docstring.empty? # Add a tag with an empty docstring object.add_tag YARD::Tags::Tag.new(:param, '', [parameter.type || 'Any'], parameter.name) next end # Warn if the parameter type and tag types don't match if parameter.type && tag.types && !tag.types.empty? && parameter.type != tag.types[0] log.warn "The type of the @param tag for parameter '#{parameter.name}' " \ "does not match the parameter type specification near #{statement.file}:#{statement.line}: " \ 'ignoring in favor of parameter type information.' end if parameter.type tag.types = [parameter.type] elsif !tag.types tag.types = ['Any'] end end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/puppet/class_handler.rb000066400000000000000000000021741466634474300323030ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/handlers/helpers' require 'puppet-strings/yard/handlers/puppet/base' require 'puppet-strings/yard/parsers' require 'puppet-strings/yard/code_objects' # Implements the handler for Puppet classes. class PuppetStrings::Yard::Handlers::Puppet::ClassHandler < PuppetStrings::Yard::Handlers::Puppet::Base handles PuppetStrings::Yard::Parsers::Puppet::ClassStatement process do # Register the object object = PuppetStrings::Yard::CodeObjects::Class.new(statement) register object # Log a warning if missing documentation log.warn "Missing documentation for Puppet class '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty? && object.tags.empty? # Set the parameter types set_parameter_types(object) # Mark the class as public if it doesn't already have an api tag object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api # Warn if a summary longer than 140 characters was provided PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/puppet/data_type_alias_handler.rb000066400000000000000000000021421466634474300343140ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/handlers/helpers' require 'puppet-strings/yard/handlers/puppet/base' require 'puppet-strings/yard/parsers' require 'puppet-strings/yard/code_objects' # Implements the handler for Puppet Data Type Alias. class PuppetStrings::Yard::Handlers::Puppet::DataTypeAliasHandler < PuppetStrings::Yard::Handlers::Puppet::Base handles PuppetStrings::Yard::Parsers::Puppet::DataTypeAliasStatement process do # Register the object object = PuppetStrings::Yard::CodeObjects::DataTypeAlias.new(statement) register object # Log a warning if missing documentation log.warn "Missing documentation for Puppet type alias '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty? && object.tags.empty? # Mark the class as public if it doesn't already have an api tag object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api # Warn if a summary longer than 140 characters was provided PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/puppet/defined_type_handler.rb000066400000000000000000000022421466634474300336310ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/handlers/helpers' require 'puppet-strings/yard/handlers/puppet/base' require 'puppet-strings/yard/parsers' require 'puppet-strings/yard/code_objects' # Implements the handler for Puppet defined types. class PuppetStrings::Yard::Handlers::Puppet::DefinedTypeHandler < PuppetStrings::Yard::Handlers::Puppet::Base handles PuppetStrings::Yard::Parsers::Puppet::DefinedTypeStatement process do # Register the object object = PuppetStrings::Yard::CodeObjects::DefinedType.new(statement) register object # Log a warning if missing documentation log.warn "Missing documentation for Puppet defined type '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty? && object.tags.empty? # Set the parameter types set_parameter_types(object) # Mark the defined type as public if it doesn't already have an api tag object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api # Warn if a summary longer than 140 characters was provided PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/puppet/function_handler.rb000066400000000000000000000037641466634474300330310ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/handlers/helpers' require 'puppet-strings/yard/handlers/puppet/base' require 'puppet-strings/yard/parsers' require 'puppet-strings/yard/code_objects' # Implements the handler for Puppet classes. class PuppetStrings::Yard::Handlers::Puppet::FunctionHandler < PuppetStrings::Yard::Handlers::Puppet::Base handles PuppetStrings::Yard::Parsers::Puppet::FunctionStatement process do # Register the object object = PuppetStrings::Yard::CodeObjects::Function.new(statement.name, PuppetStrings::Yard::CodeObjects::Function::PUPPET) object.source = statement.source object.source_type = parser.parser_type register object # Log a warning if missing documentation log.warn "Missing documentation for Puppet function '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty? && object.tags.empty? # Set the parameter tag types set_parameter_types(object) # Add a return tag add_return_tag(object, statement.type) # Set the parameters on the object object.parameters = statement.parameters.map { |p| [p.name, p.value] } # Mark the class as public if it doesn't already have an api tag object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api # Warn if a summary longer than 140 characters was provided PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary end private def add_return_tag(object, type = nil) tag = object.tag(:return) if tag if (type && tag.types && tag.types.first) && (type != tag.types.first) log.warn "Documented return type does not match return type in function definition near #{statement.file}:#{statement.line}." end tag.types = type ? [type] : tag.types || ['Any'] return end log.warn "Missing @return tag near #{statement.file}:#{statement.line}." type ||= 'Any' object.add_tag YARD::Tags::Tag.new(:return, '', type) end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/puppet/plan_handler.rb000066400000000000000000000021701466634474300321240ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/handlers/helpers' require 'puppet-strings/yard/handlers/puppet/base' require 'puppet-strings/yard/parsers' require 'puppet-strings/yard/code_objects' # Implements the handler for Puppet classes. class PuppetStrings::Yard::Handlers::Puppet::PlanHandler < PuppetStrings::Yard::Handlers::Puppet::Base handles PuppetStrings::Yard::Parsers::Puppet::PlanStatement process do # Register the object object = PuppetStrings::Yard::CodeObjects::Plan.new(statement) register object # Log a warning if missing documentation log.warn "Missing documentation for Puppet plan '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty? && object.tags.empty? # Set the parameter types set_parameter_types(object) # Mark the class as public if it doesn't already have an api tag object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api # Warn if a summary longer than 140 characters was provided PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/ruby/000077500000000000000000000000001466634474300266145ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/ruby/base.rb000066400000000000000000000041461466634474300300600ustar00rootroot00000000000000# frozen_string_literal: true require 'ripper' # Implements the base handler for Ruby language handlers. class PuppetStrings::Yard::Handlers::Ruby::Base < YARD::Handlers::Ruby::Base # A regular expression for detecting the start of a Ruby heredoc. # Note: the first character of the heredoc start may have been cut off by YARD. HEREDOC_START = /^ 1 end source when :regexp_literal node.source end end def get_name(statementobject, statementtype) parameters = statementobject.parameters(false) raise YARD::Parser::UndocumentableError, "Expected at least one parameter to #{statementtype} at #{statementobject.file}:#{statementobject.line}." if parameters.empty? name = node_as_string(parameters.first) raise YARD::Parser::UndocumentableError, "Expected a symbol or string literal for first parameter but found '#{parameters.first.type}' at #{statement.file}:#{statement.line}." unless name name end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/ruby/data_type_handler.rb000066400000000000000000000371071466634474300326200ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/handlers/helpers' require 'puppet-strings/yard/handlers/ruby/base' require 'puppet-strings/yard/code_objects' require 'puppet-strings/yard/util' # Implements the handler for Puppet Data Types written in Ruby. class PuppetStrings::Yard::Handlers::Ruby::DataTypeHandler < PuppetStrings::Yard::Handlers::Ruby::Base namespace_only handles method_call(:create_type) process do return unless statement.count > 1 ruby_module_name = statement[0].source return unless ruby_module_name == 'Puppet::DataTypes' || ruby_module_name == 'DataTypes' # rubocop:disable Style/MultipleComparison This reads better object = get_datatype_yard_object(get_name(statement, 'Puppet::DataTypes.create_type')) # Extract the interface definition type_interface = extract_data_type_interface actual_params = extract_params(type_interface) actual_funcs = extract_functions(object, type_interface) # Mark the data type as public if it doesn't already have an api tag object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api validate_param_tags!(object, actual_params) validate_methods!(object, actual_funcs) # Set the default values for all parameters actual_params.each { |name, data| object.set_parameter_default(name, data[:default]) } # Default any typeless param tag to 'Any' object.tags(:param).each do |tag| tag.types = ['Any'] unless tag.types && !tag.types.empty? end # Warn if a summary longer than 140 characters was provided PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary end private def get_datatype_yard_object(name) # Have to guess the path - if we create the object to get the true path from the code, # it also shows up in the .at call - self registering? guess_path = "puppet_data_types::#{name}" object = YARD::Registry.at(guess_path) return object unless object.nil? # Didn't find, create instead object = PuppetStrings::Yard::CodeObjects::DataType.new(name) register object object end # @return [Hash{Object => Object}] The Puppet DataType interface definition as a ruby Hash def extract_data_type_interface block = statement.block return {} unless block # Declare the parsed interface outside of the closure parsed_interface = nil # Recursively traverse the block looking for the first valid 'interface' call find_ruby_ast_node(block, true) do |node| next false unless node.is_a?(YARD::Parser::Ruby::MethodCallNode) && node.method_name && node.method_name.source == 'interface' parameters = node.parameters(false) next false unless parameters.count >= 1 interface_string = node_as_string(parameters[0]) next false unless interface_string begin # Ref - https://github.com/puppetlabs/puppet/blob/ba4d1a1aba0095d3c70b98fea5c67434a4876a61/lib/puppet/datatypes.rb#L159 parsed_interface = Puppet::Pops::Parser::EvaluatingParser.new.parse_string("{ #{interface_string} }").body rescue Puppet::Error => e log.warn "Invalid datatype definition at #{statement.file}:#{statement.line}: #{e.basic_message}" next false end !parsed_interface.nil? end # Now that we parsed the Puppet code (as a string) into a LiteralHash PCore type (Puppet AST), # We need to convert the LiteralHash into a conventional ruby hash of strings. The # LazyLiteralEvaluator does this by traversing the AST tree can converting objects to strings # where possible and ignoring object types which cannot (thus the 'Lazy' name) literal_eval = LazyLiteralEvaluator.new literal_eval.literal(parsed_interface) end # Find the first Ruby AST node within an AST Tree, optionally recursively. Returns nil of none could be found # # @param [YARD::Parser::Ruby::AstNode] ast_node The root AST node object to inspect # @param [Boolean] recurse Whether to search the tree recursively. Defaults to false # @yieldparam [YARD::Parser::Ruby::AstNode] ast_node The AST Node that should be checked # @yieldreturn [Boolean] Whether the node was what was searched for # @return [YARD::Parser::Ruby::AstNode, nil] def find_ruby_ast_node(ast_node, recurse = false, &block) raise ArgumentError, 'find_ruby_ast_node requires a block' unless block is_found = yield ast_node return ast_node if is_found if ast_node.respond_to?(:children) ast_node.children.each do |child_node| child_found = find_ruby_ast_node(child_node, recurse, &block) return child_found unless child_found.nil? end end nil end # Lazily evaluates a Pops object, ignoring any objects that cannot # be converted to a literal value. Based on the Puppet Literal Evaluator # Ref - https://github.com/puppetlabs/puppet/blob/ba4d1a1aba0095d3c70b98fea5c67434a4876a61/lib/puppet/pops/evaluator/literal_evaluator.rb # # Literal values for: # String (not containing interpolation) # Numbers # Booleans # Undef (produces nil) # Array # Hash # QualifiedName # Default (produced :default) # Regular Expression (produces ruby regular expression) # QualifiedReference e.g. File, FooBar # AccessExpression # # Anything else is ignored class LazyLiteralEvaluator def initialize @literal_visitor = ::Puppet::Pops::Visitor.new(self, 'literal', 0, 0) end def literal(ast) @literal_visitor.visit_this_0(self, ast) end # TODO: Fix the rubocop violations in this file between the following rubocop:disable/enable lines # rubocop:disable Naming/MethodName # ----- The following methods are different/additions from the original Literal_evaluator def literal_Object(o) # Ignore any other object types end def literal_AccessExpression(o) # Extract the raw text of the Access Expression PuppetStrings::Yard::Util.ast_to_text(o) end def literal_QualifiedReference(o) # Extract the raw text of the Qualified Reference PuppetStrings::Yard::Util.ast_to_text(o) end # ----- The following methods are the same as the original Literal_evaluator def literal_Factory(o) literal(o.model) end def literal_Program(o) literal(o.body) end def literal_LiteralString(o) o.value end def literal_QualifiedName(o) o.value end def literal_LiteralNumber(o) o.value end def literal_UnaryMinusExpression(o) -1 * literal(o.expr) end def literal_LiteralBoolean(o) o.value end def literal_LiteralUndef(_o) nil end def literal_LiteralDefault(_o) :default end def literal_LiteralRegularExpression(o) o.value end def literal_ConcatenatedString(o) # use double quoted string value if there is no interpolation throw :not_literal unless o.segments.size == 1 && o.segments[0].is_a?(Model::LiteralString) o.segments[0].value end def literal_LiteralList(o) o.values.map { |v| literal(v) } end def literal_LiteralHash(o) o.entries.each_with_object({}) do |entry, result| result[literal(entry.key)] = literal(entry.value) end end # rubocop:enable Naming/MethodName end # Extracts the datatype attributes from a Puppet Data Type interface hash. # Returns a Hash with a :types key (Array of data types for the parameter) and :default key (The default value of the parameter) # @return Hash[Symbol => Hash] The Datatype Attributes as a hash def extract_params(hash) params_hash = {} # Exit early if there are no entries in the hash return params_hash if hash.nil? || hash['attributes'].nil? || hash['attributes'].empty? hash['attributes'].each do |key, value| data_type = nil default = nil if value.is_a?(String) data_type = value elsif value.is_a?(Hash) data_type = value['type'] unless value['type'].nil? default = value['value'] unless value['value'].nil? end data_type = [data_type] unless data_type.nil? || data_type.is_a?(Array) params_hash[key] = { types: data_type, default: default } end params_hash end # Extracts the datatype functions from a Puppet Data Type interface hash. # Returns a Hash with a :param_types key (Array of types for each parameter) and :return_type key (The return type of the function) # @return Hash[Symbol => Hash] The Datatype Attributes as a hash def extract_functions(object, hash) funcs_hash = {} # Exit early if there are no entries in the hash return funcs_hash if hash.nil? || hash['functions'].nil? || hash['functions'].empty? hash['functions'].each do |key, func_type| func_hash = { param_types: [], return_type: nil } begin callable_type = Puppet::Pops::Types::TypeParser.singleton.parse(func_type) if callable_type.is_a?(Puppet::Pops::Types::PCallableType) func_hash[:param_types] = callable_type.param_types.map(&:to_s) func_hash[:return_type] = callable_type.return_type.to_s else log.warn "The function definition for '#{key}' near #{object.file}:#{object.line} is not a Callable type" end rescue Puppet::ParseError => e log.warn "Unable to parse the function definition for '#{key}' near #{object.file}:#{object.line}. #{e}" end funcs_hash[key] = func_hash end funcs_hash end # Validates and automatically fixes yard @param tags for the data type def validate_param_tags!(object, actual_params_hash) actual_param_names = actual_params_hash.keys tagged_param_names = object.tags(:param).map(&:name) # Log any errors # Find attributes which are not documented (actual_param_names - tagged_param_names).each do |item| log.warn "Missing @param tag for attribute '#{item}' near #{object.file}:#{object.line}." end # Find param tags with no matching attribute (tagged_param_names - actual_param_names).each do |item| log.warn "The @param tag for '#{item}' has no matching attribute near #{object.file}:#{object.line}." end # Find param tags with a type that is different from the actual definition object.tags(:param).reject { |tag| tag.types.nil? }.each do |tag| next if actual_params_hash[tag.name].nil? actual_data_type = actual_params_hash[tag.name][:types] next if actual_data_type.nil? log.warn "The @param tag for '#{tag.name}' has a different type definition than the actual attribute near #{object.file}:#{object.line}." if tag.types != actual_data_type end # Automatically fix missing @param tags (actual_param_names - tagged_param_names).each do |name| object.add_parameter(name, actual_params_hash[name][:types], actual_params_hash[name][:default]) end # Remove extra param tags object.docstring.delete_tag_if { |item| item.tag_name == 'param' && !actual_param_names.include?(item.name) } # Set the type in the param tag object.tags(:param).each do |tag| next if actual_params_hash[tag.name].nil? tag.types = actual_params_hash[tag.name][:types] end end # Validates and automatically fixes yard @method! tags for the data type def validate_methods!(object, actual_functions_hash) actual_func_names = actual_functions_hash.keys tagged_func_names = object.meths.map { |meth| meth.name.to_s } # Log any errors # Find functions which are not documented (actual_func_names - tagged_func_names).each do |item| log.warn "Missing @!method tag for function '#{item}' near #{object.file}:#{object.line}." end # Find functions which are not defined (tagged_func_names - actual_func_names).each do |item| log.warn "The @!method tag for '#{item}' has no matching function definition near #{object.file}:#{object.line}." end # Functions with the wrong return type object.meths.each do |meth| next unless actual_func_names.include?(meth.name.to_s) return_tag = meth.docstring.tag(:return) next if return_tag.nil? actual_return_types = [actual_functions_hash[meth.name.to_s][:return_type]] next if return_tag.types == actual_return_types log.warn "The @return tag for '#{meth.name}' has a different type definition than the actual function near #{object.file}:#{object.line}. Expected #{actual_return_types}" return_tag.types = actual_return_types end # Automatically fix missing methods (actual_func_names - tagged_func_names).each do |name| object.add_function(name, actual_functions_hash[name][:return_type], actual_functions_hash[name][:param_types]) end # Remove extra methods. Can't use `meths` as that's a derived property object.children.reject! { |child| child.is_a?(YARD::CodeObjects::MethodObject) && !actual_func_names.include?(child.name.to_s) } # Add the return type for the methods if missing object.meths.each do |meth| next unless meth.docstring.tag(:return).nil? meth.docstring.add_tag(YARD::Tags::Tag.new(:return, '', actual_functions_hash[meth.name.to_s][:return_type])) end # Sync the method properties and add the return type for the methods if missing object.meths.each do |meth| validate_function_method!(object, meth, actual_functions_hash[meth.name.to_s]) next unless meth.docstring.tag(:return).nil? meth.docstring.add_tag(YARD::Tags::Tag.new(:return, '', actual_functions_hash[meth.name.to_s][:return_type])) end # The default meth.signature assumes ruby invocation (e.g. def meth(...)) but this doesn't make sense for a # Puppet Data Type function invocation. So instead we derive a signature from the method definition. object.meths.each do |meth| params = '' params += "(#{meth.docstring.tags(:param).map(&:name).join(', ')})" unless meth.docstring.tags(:param).empty? meth.signature = "#{object.name}.#{meth.name}" + params end nil end # Validates and automatically fixes a single yard @method! # Used by the validate_methods! method. def validate_function_method!(object, meth, actual_function) # Remove extra params if meth.docstring.tags(:param).count > actual_function[:param_types].count index = 0 meth.docstring.delete_tag_if do |tag| if tag.tag_name == 'param' index += 1 if index > actual_function[:param_types].count log.warn "The @param tag for '#{tag.name}' should not exist for function " \ "'#{meth.name}' that is defined near #{object.file}:#{object.line}. " \ "Expected only #{actual_function[:param_types].count} parameter/s" true else false end else false end end end # Add missing params if meth.docstring.tags(:param).count < actual_function[:param_types].count start = meth.docstring.tags(:param).count + 1 (start..actual_function[:param_types].count).each do |param_type_index| # Using 1-based index here instead of usual zero meth.add_tag(YARD::Tags::Tag.new(:param, '', actual_function[:param_types][param_type_index - 1], "param#{param_type_index}")) end end # Ensure the parameter types are correct meth.docstring.tags(:param).each_with_index do |tag, actual_type_index| actual_types = [actual_function[:param_types][actual_type_index]] if tag.types != actual_types log.warn "The @param tag for '#{tag.name}' for function '#{meth.name}' has a different type definition than the actual function near #{object.file}:#{object.line}. Expected #{actual_types}" tag.types = actual_types end end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/ruby/function_handler.rb000066400000000000000000000301061466634474300324630ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/handlers/helpers' require 'puppet-strings/yard/handlers/ruby/base' require 'puppet-strings/yard/code_objects' require 'puppet-strings/yard/util' # Implements the handler for Puppet functions written in Ruby. class PuppetStrings::Yard::Handlers::Ruby::FunctionHandler < PuppetStrings::Yard::Handlers::Ruby::Base # Represents the list of Puppet 4.x function API methods to support. DISPATCH_METHOD_NAMES = %w[ param required_param optional_param repeated_param optional_repeated_param required_repeated_param block_param required_block_param optional_block_param return_type ].freeze namespace_only handles method_call(:create_function) handles method_call(:newfunction) process do # Only accept calls to Puppet::Functions (4.x) or Puppet::Parser::Functions (3.x) # When `newfunction` is separated from the Puppet::Parser::Functions module name by a # newline, YARD ignores the namespace and uses `newfunction` as the source of the # first statement. return unless statement.count > 1 module_name = statement[0].source return unless ['Puppet::Functions', 'Puppet::Parser::Functions', 'newfunction'].include?(module_name) # Create and register the function object is_3x = ['Puppet::Parser::Functions', 'newfunction'].include?(module_name) object = PuppetStrings::Yard::CodeObjects::Function.new( get_name(statement, 'Puppet::Functions.create_function'), is_3x ? PuppetStrings::Yard::CodeObjects::Function::RUBY_3X : PuppetStrings::Yard::CodeObjects::Function::RUBY_4X ) object.source = statement register object # For 3x, parse the doc parameter for the docstring # This must be done after the `register` call above because `register` always uses the statement's docstring if is_3x docstring = get_3x_docstring(object.name) register_docstring(object, docstring, nil) if docstring # Default any typeless param tag to 'Any' object.tags(:param).each do |tag| tag.types = ['Any'] unless tag.types && !tag.types.empty? end # Populate the parameters and the return tag object.parameters = object.tags(:param).map { |p| [p.name, nil] } add_return_tag(object, statement.file, statement.line) else # For 4x, auto generate tags based on dispatch docstrings add_tags(object) end # Mark the function as public if it doesn't already have an api tag object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api # Warn if a summary longer than 140 characters was provided PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary end private def add_tags(object) log.warn "Missing documentation for Puppet function '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty? && object.tags.empty? unless object.tags(:param).empty? log.warn "The docstring for Puppet 4.x function '#{object.name}' " \ "contains @param tags near #{object.file}:#{object.line}: parameter " \ 'documentation should be made on the dispatch call.' end unless object.tags(:return).empty? log.warn "The docstring for Puppet 4.x function '#{object.name}' " \ "contains @return tags near #{object.file}:#{object.line}: return " \ 'value documentation should be made on the dispatch call.' end unless object.tags(:overload).empty? log.warn "The docstring for Puppet 4.x function '#{object.name}' " \ "contains @overload tags near #{object.file}:#{object.line}: overload " \ 'tags are automatically generated from the dispatch calls.' end # Delete any existing param/return/overload tags object.docstring.delete_tags(:param) object.docstring.delete_tags(:return) object.docstring.delete_tags(:overload) block = statement.block return unless block && block.count >= 2 # Get the unqualified name of the Puppet function unqualified_name = object.name.to_s.split('::').last # Walk the block statements looking for dispatch calls and methods with the same name as the Puppet function default = nil block[1].children.each do |node| if node.is_a?(YARD::Parser::Ruby::MethodCallNode) add_overload_tag(object, node) elsif node.is_a?(YARD::Parser::Ruby::MethodDefinitionNode) default = node if node.method_name && node.method_name.source == unqualified_name end end # Create an overload for the default method if there is one overloads = object.tags(:overload) if overloads.empty? && default add_method_overload(object, default) overloads = object.tags(:overload) end # If there's only one overload, move the tags to the object itself return unless overloads.length == 1 overload = overloads.first object.parameters = overload.parameters object.add_tag(*overload.tags) object.docstring.delete_tags(:overload) end def add_overload_tag(object, node) # Look for a call to a dispatch method with a block return unless node.is_a?(YARD::Parser::Ruby::MethodCallNode) && node.method_name && node.method_name.source == 'dispatch' && node.parameters(false).count == 1 && node.block && node.block.count >= 2 overload_tag = PuppetStrings::Yard::Tags::OverloadTag.new(object.name, node.docstring || '') param_tags = overload_tag.tags(:param) block = nil node.block[1].children.each do |child| next unless child.is_a?(YARD::Parser::Ruby::MethodCallNode) && child.method_name method_name = child.method_name.source next unless DISPATCH_METHOD_NAMES.include?(method_name) if method_name == 'return_type' # Add a return tag if missing overload_tag.add_tag YARD::Tags::Tag.new(:return, '', 'Any') if overload_tag.tag(:return).nil? overload_tag.tag(:return).types = [node_as_string(child.parameters[0])] next end # Check for block if method_name.include?('block') if block log.warn "A duplicate block parameter was found for Puppet function '#{object.name}' at #{child.file}:#{child.line}." next end # Store the block; needs to be appended last block = child next end # Ensure two parameters to parameter definition parameters = child.parameters(false) unless parameters.count == 2 log.warn "Expected 2 arguments to '#{method_name}' call at #{child.file}:#{child.line}: parameter information may not be correct." next end add_param_tag( overload_tag, param_tags, node_as_string(parameters[1]), child.file, child.line, node_as_string(parameters[0]), nil, # TODO: determine default from corresponding Ruby method signature? method_name.include?('optional'), method_name.include?('repeated') ) end # Handle the block parameter after others so it appears last in the list if block parameters = block.parameters(false) if parameters.empty? name = 'block' type = 'Callable' elsif parameters.count == 1 name = node_as_string(parameters[0]) type = 'Callable' elsif parameters.count == 2 type = node_as_string(parameters[0]) name = node_as_string(parameters[1]) else log.warn "Unexpected number of arguments to block definition at #{block.file}:#{block.line}." end if name && type add_param_tag( overload_tag, param_tags, name, block.file, block.line, type, nil, # TODO: determine default from corresponding Ruby method signature? block.method_name.source.include?('optional'), false, # Not repeated true # Is block ) end end # Add a return tag if missing add_return_tag(overload_tag, node.file, node.line) # Validate that tags have parameters validate_overload(overload_tag, node.file, node.line) object.add_tag overload_tag end def add_method_overload(object, node) overload_tag = PuppetStrings::Yard::Tags::OverloadTag.new(object.name, node.docstring || '') param_tags = overload_tag.tags(:param) parameters = node.parameters # Populate the required parameters params = parameters.unnamed_required_params params&.each do |parameter| add_param_tag( overload_tag, param_tags, parameter.source, parameter.file, parameter.line ) end # Populate the optional parameters params = parameters.unnamed_optional_params params&.each do |parameter| add_param_tag( overload_tag, param_tags, parameter[0].source, parameter.file, parameter.line, nil, parameter[1].source, true ) end # Populate the splat parameter param = parameters.splat_param if param add_param_tag( overload_tag, param_tags, param.source, param.file, param.line, nil, nil, false, true ) end # Populate the block parameter param = parameters.block_param if param add_param_tag( overload_tag, param_tags, param.source, param.file, param.line, nil, nil, false, false, true ) end # Add a return tag if missing add_return_tag(overload_tag, node.file, node.line) # Validate that tags have parameters validate_overload(overload_tag, node.file, node.line) object.add_tag overload_tag end def add_param_tag(object, tags, name, file, line, type = nil, default = nil, optional = false, repeated = false, block = false) tag = tags.find { |t| t.name == name } if tags log.warn "Missing @param tag for parameter '#{name}' near #{file}:#{line}." unless tag || object.docstring.all.empty? if type && tag && tag.types && !tag.types.empty? log.warn "The @param tag for parameter '#{name}' should not contain a " \ "type specification near #{file}:#{line}: ignoring in favor of " \ 'dispatch type information.' end if repeated name = "*#{name}" elsif block name = "&#{name}" end type ||= tag&.types ? tag.type : 'Any' type = "Optional[#{type}]" if optional object.parameters << [name, to_puppet_literal(default)] if tag tag.name = name tag.types = [type] else object.add_tag YARD::Tags::Tag.new(:param, '', type, name) end end def add_return_tag(object, file, line) tag = object.tag(:return) if tag tag.types = ['Any'] unless tag.types return end log.warn "Missing @return tag near #{file}:#{line}." object.add_tag YARD::Tags::Tag.new(:return, '', 'Any') end def validate_overload(overload, file, line) # Validate that tags have matching parameters overload.tags(:param).each do |tag| next if overload.parameters.find { |p| tag.name == p[0] } log.warn "The @param tag for parameter '#{tag.name}' has no matching parameter at #{file}:#{line}." end end def get_3x_docstring(name) parameters = statement.parameters(false) if parameters.count >= 2 parameters[1].each do |kvp| next unless kvp.count == 2 next unless node_as_string(kvp[0]) == 'doc' docstring = node_as_string(kvp[1]) log.error "Failed to parse docstring for 3.x Puppet function '#{name}' near #{statement.file}:#{statement.line}." and return nil unless docstring return PuppetStrings::Yard::Util.scrub_string(docstring) end end # Log a warning for missing docstring log.warn "Missing documentation for Puppet function '#{name}' at #{statement.file}:#{statement.line}." nil end def to_puppet_literal(literal) case literal when 'nil' 'undef' when ':default' 'default' else literal end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/ruby/provider_handler.rb000066400000000000000000000115261466634474300324750ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/handlers/helpers' require 'puppet-strings/yard/handlers/ruby/base' require 'puppet-strings/yard/code_objects' require 'puppet-strings/yard/util' # Implements the handler for Puppet providers written in Ruby. class PuppetStrings::Yard::Handlers::Ruby::ProviderHandler < PuppetStrings::Yard::Handlers::Ruby::Base namespace_only handles method_call(:provide) process do return unless statement.count >= 2 # Check that provide is being called on Puppet::Type.type() type_call = statement[0] return unless type_call.is_a?(YARD::Parser::Ruby::MethodCallNode) && type_call.count >= 3 return unless type_call[0].source == 'Puppet::Type' return unless type_call[2].source == 'type' # Extract the type name type_call_parameters = type_call.parameters(false) return unless type_call_parameters.count >= 1 type_name = node_as_string(type_call_parameters.first) raise YARD::Parser::UndocumentableError, "Could not determine the resource type name for the provider defined at #{statement.file}:#{statement.line}." unless type_name # Register the object object = PuppetStrings::Yard::CodeObjects::Provider.new(type_name, get_name(statement, "'provide'")) register object # Extract the docstring register_provider_docstring object # Populate the provider data populate_provider_data object # Mark the provider as public if it doesn't already have an api tag object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api # Warn if a summary longer than 140 characters was provided PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary end private def register_provider_docstring(object) # Walk the tree searching for assignments or calls to desc/doc= statement.traverse do |child| if child.type == :assign ivar = child.jump(:ivar) next unless ivar != child && ivar.source == '@doc' docstring = node_as_string(child[1]) log.error "Failed to parse docstring for Puppet provider '#{object.name}' (resource type '#{object.type_name}') near #{child.file}:#{child.line}." and return nil unless docstring register_docstring(object, PuppetStrings::Yard::Util.scrub_string(docstring), nil) return nil elsif child.is_a?(YARD::Parser::Ruby::MethodCallNode) # Look for a call to a dispatch method with a block next unless child.method_name && (child.method_name.source == 'desc' || child.method_name.source == 'doc=') && child.parameters(false).count == 1 docstring = node_as_string(child.parameters[0]) log.error "Failed to parse docstring for Puppet provider '#{object.name}' (resource type '#{object.type_name}') near #{child.file}:#{child.line}." and return nil unless docstring register_docstring(object, PuppetStrings::Yard::Util.scrub_string(docstring), nil) return nil end end log.warn "Missing a description for Puppet provider '#{object.name}' (resource type '#{object.type_name}') at #{statement.file}:#{statement.line}." end def populate_provider_data(object) # Traverse the block looking for confines/defaults/commands block = statement.block return unless block && block.count >= 2 block[1].children.each do |node| next unless node.is_a?(YARD::Parser::Ruby::MethodCallNode) && node.method_name method_name = node.method_name.source parameters = node.parameters(false) if method_name == 'confine' # Add a confine to the object next unless parameters.count >= 1 parameters[0].each do |kvp| next unless kvp.count == 2 object.add_confine(node_as_string(kvp[0]) || kvp[0].source, node_as_string(kvp[1]) || kvp[1].source) end elsif %w[has_feature has_features].include?(method_name) # Add the features to the object parameters.each do |parameter| object.add_feature(node_as_string(parameter) || parameter.source) end elsif method_name == 'defaultfor' # Add a default to the object next unless parameters.count >= 1 # Some defaultfor statements contain multiple constraints. parameters.each do |kvps| next unless kvps.count >= 1 defaultfor = kvps.map do |kvp| [node_as_string(kvp[0]) || kvp[0].source, node_as_string(kvp[1]) || kvp[1].source] end object.add_default(defaultfor) end elsif method_name == 'commands' # Add the commands to the object next unless parameters.count >= 1 parameters[0].each do |kvp| next unless kvp.count == 2 object.add_command(node_as_string(kvp[0]) || kvp[0].source, node_as_string(kvp[1]) || kvp[1].source) end end end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/ruby/rsapi_handler.rb000066400000000000000000000112661466634474300317620ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/handlers/helpers' require 'puppet-strings/yard/handlers/ruby/base' require 'puppet-strings/yard/code_objects' require 'puppet-strings/yard/util' # Implements the handler for Puppet resource types written in Ruby. class PuppetStrings::Yard::Handlers::Ruby::RsapiHandler < PuppetStrings::Yard::Handlers::Ruby::Base # The default docstring when ensurable is used without given a docstring. DEFAULT_ENSURABLE_DOCSTRING = 'The basic property that the resource should be in.' namespace_only handles method_call(:register_type) process do # Only accept calls to Puppet::ResourceApi return unless statement.count > 1 module_name = statement[0].source return unless ['Puppet::ResourceApi'].include? module_name schema = extract_schema # puts "Schema: #{schema.inspect}" object = PuppetStrings::Yard::CodeObjects::Type.new(schema['name']) register object docstring = schema['docs'] if docstring register_docstring(object, PuppetStrings::Yard::Util.scrub_string(docstring.to_s), nil) else log.warn "Missing a description for Puppet resource type '#{object.name}' at #{statement.file}:#{statement.line}." end # Populate the parameters/properties/features to the type populate_type_data(object, schema) # Mark the type as public if it doesn't already have an api tag object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api # Warn if a summary longer than 140 characters was provided PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary end private def raise_parse_error(msg, location = statement) raise YARD::Parser::UndocumentableError, "#{msg} at #{location.file}:#{location.line}." end # check that the params of the register_type call are key/value pairs. def kv_arg_list?(params) params.type == :list && params.children.count.positive? && params.children.first.type == :list && params.children.first.children.count.positive? && statement.parameters.children.first.children.first.type == :assoc end def extract_schema raise_parse_error('Expected list of key/value pairs as argument') unless kv_arg_list?(statement.parameters) hash_from_node(statement.parameters.children.first) end def value_from_node(node) return nil unless node # puts "value from #{node.inspect}" case node.type when :int node.source.to_i when :hash hash_from_node(node) when :array array_from_node(node) when :var_ref var_ref_from_node(node) when :symbol, :symbol_literal, :label, :dyna_symbol, :string_literal, :regexp_literal node_as_string(node) else raise_parse_error("unexpected construct #{node.type}") end end def array_from_node(node) return nil unless node node.children.map do |assoc| value_from_node(assoc.children[0]) end end def hash_from_node(node) return nil unless node # puts "hash from #{node.inspect}" kv_pairs = node.children.map do |assoc| [value_from_node(assoc.children[0]), value_from_node(assoc.children[1])] end kv_pairs.to_h end def var_ref_from_node(node) return nil unless node # puts "var_ref from #{node.inspect}" if node.children.first.type == :kw case node.children.first.source when 'false' return false when 'true' return true when 'nil' return nil else raise_parse_error("unexpected keyword '#{node.children.first.source}'") end end raise_parse_error('unexpected variable') end def populate_type_data(object, schema) return if schema['attributes'].nil? schema['attributes'].each do |name, definition| # puts "Processing #{name}: #{definition.inspect}" if %w[parameter namevar].include? definition['behaviour'] object.add_parameter(create_parameter(name, definition)) else object.add_property(create_property(name, definition)) end end end def create_parameter(name, definition) parameter = PuppetStrings::Yard::CodeObjects::Type::Parameter.new(name, definition['desc']) set_values(definition, parameter) parameter end def create_property(name, definition) property = PuppetStrings::Yard::CodeObjects::Type::Property.new(name, definition['desc']) set_values(definition, property) property end def set_values(definition, object) object.data_type = definition['type'] if definition.key? 'type' object.default = definition['default'] if definition.key? 'default' object.isnamevar = definition.key?('behaviour') && definition['behaviour'] == 'namevar' end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/ruby/type_base.rb000066400000000000000000000122111466634474300311110ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/handlers/ruby/base' # Base class for all Puppet resource type handlers. class PuppetStrings::Yard::Handlers::Ruby::TypeBase < PuppetStrings::Yard::Handlers::Ruby::Base protected def get_type_yard_object(name) # Have to guess the path - if we create the object to get the true path from the code, # it also shows up in the .at call - self registering? guess_path = "puppet_types::#{name}" object = YARD::Registry.at(guess_path) return object unless object.nil? # Didn't find, create instead object = PuppetStrings::Yard::CodeObjects::Type.new(name) register object object end def find_docstring(node, kind) # Walk the tree searching for assignments or calls to desc/doc= node.traverse do |child| if child.type == :assign ivar = child.jump(:ivar) next unless ivar != child && ivar.source == '@doc' docstring = node_as_string(child[1]) log.error "Failed to parse docstring for #{kind} near #{child.file}:#{child.line}." and return nil unless docstring return PuppetStrings::Yard::Util.scrub_string(docstring) elsif child.is_a?(YARD::Parser::Ruby::MethodCallNode) # Look for a call to a dispatch method with a block next unless child.method_name && (child.method_name.source == 'desc' || child.method_name.source == 'doc=') && child.parameters(false).count == 1 docstring = node_as_string(child.parameters[0]) log.error "Failed to parse docstring for #{kind} near #{child.file}:#{child.line}." and return nil unless docstring return PuppetStrings::Yard::Util.scrub_string(docstring) end end log.warn "Missing a description for #{kind} at #{node.file}:#{node.line}." nil end def create_parameter(name, node) parameter = PuppetStrings::Yard::CodeObjects::Type::Parameter.new(name, find_docstring(node, "Puppet resource parameter '#{name}'")) set_values(node, parameter) parameter end def create_property(name, node) property = PuppetStrings::Yard::CodeObjects::Type::Property.new(name, find_docstring(node, "Puppet resource property '#{name}'")) set_values(node, property) property end def create_check(name, node) check = PuppetStrings::Yard::CodeObjects::Type::Check.new(name, find_docstring(node, "Puppet resource check '#{name}'")) set_values(node, check) check end def set_values(node, object) return unless node.block && node.block.count >= 2 node.block[1].children.each do |child| next unless child.is_a?(YARD::Parser::Ruby::MethodCallNode) && child.method_name method_name = child.method_name.source parameters = child.parameters(false) if method_name == 'newvalue' next unless parameters.count >= 1 object.add(node_as_string(parameters[0]) || parameters[0].source) elsif method_name == 'newvalues' parameters.each do |p| object.add(node_as_string(p) || p.source) end elsif method_name == 'aliasvalue' next unless parameters.count >= 2 object.alias(node_as_string(parameters[0]) || parameters[0].source, node_as_string(parameters[1]) || parameters[1].source) elsif method_name == 'defaultto' next unless parameters.count >= 1 object.default = node_as_string(parameters[0]) || parameters[0].source elsif method_name == 'isnamevar' object.isnamevar = true elsif method_name == 'defaultvalues' && object.name == 'ensure' object.add('present') object.add('absent') object.default = 'present' end end parameters = node.parameters(false) if parameters.count >= 2 kvps = parameters[1].select { |kvp| kvp.count == 2 } required_features_kvp = kvps.find { |kvp| node_as_string(kvp[0]) == 'required_features' } object.required_features = node_as_string(required_features_kvp[1]) unless required_features_kvp.nil? end return unless object.is_a? PuppetStrings::Yard::CodeObjects::Type::Parameter # Process the options for parameter base types return unless parameters.count >= 2 parameters[1].each do |kvp| next unless kvp.count == 2 next unless node_as_string(kvp[0]) == 'parent' if kvp[1].source == 'Puppet::Parameter::Boolean' # rubocop:disable Performance/InefficientHashSearch object.add('true') unless object.values.include? 'true' object.add('false') unless object.values.include? 'false' object.add('yes') unless object.values.include? 'yes' object.add('no') unless object.values.include? 'no' # rubocop:enable Performance/InefficientHashSearch end break end end def set_default_namevar(object) return unless object.properties || object.parameters default = nil object.properties&.each do |property| return nil if property.isnamevar default = property if property.name == 'name' end object.parameters&.each do |parameter| return nil if parameter.isnamevar default ||= parameter if parameter.name == 'name' end default.isnamevar = true if default end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/ruby/type_extras_handler.rb000066400000000000000000000047201466634474300332100ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/handlers/helpers' require 'puppet-strings/yard/handlers/ruby/type_base' require 'puppet-strings/yard/code_objects' require 'puppet-strings/yard/util' # Implements the handler for Puppet resource type newparam/newproperty/ensurable calls written in Ruby. class PuppetStrings::Yard::Handlers::Ruby::TypeExtrasHandler < PuppetStrings::Yard::Handlers::Ruby::TypeBase # The default docstring when ensurable is used without given a docstring. DEFAULT_ENSURABLE_DOCSTRING = 'The basic property that the resource should be in.' namespace_only handles method_call(:newparam) handles method_call(:newproperty) handles method_call(:ensurable) process do # Our entry point is a type newproperty/newparam compound statement like this: # "Puppet::Type.type(:file).newparam(:content) do" # We want to # Verify the structure # Capture the three parameters (e.g. type: 'file', newproperty or newparam?, name: 'source') # Proceed with collecting data # Either decorate an existing type object or store for future type object parsing # Only accept calls to Puppet::Type.type().newparam/.newproperty # e.g. "Puppet::Type.type(:file).newparam(:content) do" would yield: # module_name: "Puppet::Type" # method1_name: "type" # typename: "file" # method2_name: "newparam" # propertyname: "content" return unless (statement.count > 1) && (statement[0].children.count > 2) module_name = statement[0].children[0].source method1_name = statement[0].children.drop(1).find { |c| c.type == :ident }.source return unless ['Type', 'Puppet::Type'].include?(module_name) && method1_name == 'type' # ensurable is syntatic sugar for newproperty typename = get_name(statement[0], 'Puppet::Type.type') if caller_method == 'ensurable' method2_name = 'newproperty' propertyname = 'ensure' else method2_name = caller_method propertyname = get_name(statement, "Puppet::Type.type().#{method2_name}") end typeobject = get_type_yard_object(typename) # node - what should it be here? node = statement # ?? not sure... test... if method2_name == 'newproperty' typeobject.add_property(create_property(propertyname, node)) elsif method2_name == 'newparam' typeobject.add_parameter(create_parameter(propertyname, node)) end # Set the default namevar set_default_namevar(typeobject) end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/handlers/ruby/type_handler.rb000066400000000000000000000066151466634474300316270ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/handlers/helpers' require 'puppet-strings/yard/handlers/ruby/type_base' require 'puppet-strings/yard/code_objects' require 'puppet-strings/yard/util' # Implements the handler for Puppet resource types written in Ruby. class PuppetStrings::Yard::Handlers::Ruby::TypeHandler < PuppetStrings::Yard::Handlers::Ruby::TypeBase # The default docstring when ensurable is used without given a docstring. DEFAULT_ENSURABLE_DOCSTRING = 'The basic property that the resource should be in.' namespace_only handles method_call(:newtype) process do # Only accept calls to Puppet::Type return unless statement.count > 1 module_name = statement[0].source return unless ['Puppet::Type', 'Type'].include?(module_name) object = get_type_yard_object(get_name(statement, 'Puppet::Type.newtype')) docstring = find_docstring(statement, "Puppet resource type '#{object.name}'") register_docstring(object, docstring, nil) if docstring # Populate the parameters/properties/features to the type populate_type_data(object) # Set the default namevar set_default_namevar(object) # Mark the type as public if it doesn't already have an api tag object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api # Warn if a summary longer than 140 characters was provided PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary end private def populate_type_data(object) # Traverse the block looking for properties/parameters/features block = statement.block return unless block && block.count >= 2 block[1].children.each do |node| next unless node.is_a?(YARD::Parser::Ruby::MethodCallNode) && node.method_name method_name = node.method_name.source parameters = node.parameters(false) case method_name when 'newproperty' # Add a property to the object next unless parameters.count >= 1 name = node_as_string(parameters[0]) next unless name object.add_property(create_property(name, node)) when 'newparam' # Add a parameter to the object next unless parameters.count >= 1 name = node_as_string(parameters[0]) next unless name object.add_parameter(create_parameter(name, node)) when 'newcheck' # Add a check to the object next unless parameters.count >= 1 name = node_as_string(parameters[0]) next unless name object.add_check(create_check(name, node)) when 'feature' # Add a feature to the object next unless parameters.count >= 2 name = node_as_string(parameters[0]) next unless name docstring = node_as_string(parameters[1]) next unless docstring object.add_feature(PuppetStrings::Yard::CodeObjects::Type::Feature.new(name, docstring)) when 'ensurable' if node.block property = create_property('ensure', node) property.docstring = DEFAULT_ENSURABLE_DOCSTRING if property.docstring.empty? else property = PuppetStrings::Yard::CodeObjects::Type::Property.new('ensure', DEFAULT_ENSURABLE_DOCSTRING) property.add('present') property.add('absent') property.default = 'present' end object.add_property property end end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/parsers.rb000066400000000000000000000005671466634474300260470ustar00rootroot00000000000000# frozen_string_literal: true # The module for custom YARD parsers. module PuppetStrings::Yard::Parsers # The module for custom YARD parsers for JSON. module JSON require 'puppet-strings/yard/parsers/json/parser' end # The module for custom YARD parsers for the Puppet language. module Puppet require 'puppet-strings/yard/parsers/puppet/parser' end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/parsers/000077500000000000000000000000001466634474300255125ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/parsers/json/000077500000000000000000000000001466634474300264635ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/parsers/json/parser.rb000066400000000000000000000020761466634474300303110ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/parsers/json/task_statement' # Implementas a JSON parser. class PuppetStrings::Yard::Parsers::JSON::Parser < YARD::Parser::Base attr_reader :file, :source # Initializes the parser. # @param [String] source The source being parsed. # @param [String] filename The file name of the file being parsed. # @return [void] def initialize(source, filename) # rubocop:disable Lint/MissingSuper @file = filename @source = source @statements = [] end def enumerator @statements end # Parses the source # @return [void] def parse begin json = JSON.parse(source) # TODO: this should compare json to a Task metadata json-schema or perform some other hueristics # to determine what type of statement it represents @statements.push(PuppetStrings::Yard::Parsers::JSON::TaskStatement.new(json, @source, @file)) unless json.empty? rescue StandardError log.error "Failed to parse #{@file}: " @statements = [] end @statements.freeze self end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/parsers/json/task_statement.rb000066400000000000000000000012641466634474300320410ustar00rootroot00000000000000# frozen_string_literal: true module PuppetStrings::Yard::Parsers::JSON # Represents the Puppet Task statement. class TaskStatement attr_reader :line, :comments_range, :json, :file, :source, :docstring def initialize(json, source, file) @file = file @source = source @json = json @line = 0 @comments_range = nil @docstring = YARD::Docstring.new(@json['description']) end def parameters json['parameters'] || {} end def comments_hash_flag false end def show '' end def comments docstring.all end def name File.basename(@file).gsub('.json', '') || '' end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/parsers/puppet/000077500000000000000000000000001466634474300270275ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/parsers/puppet/parser.rb000066400000000000000000000051531466634474300306540ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet' require 'puppet/pops' require 'puppet-strings/yard/parsers/puppet/statement' # Implements the Puppet language parser. class PuppetStrings::Yard::Parsers::Puppet::Parser < YARD::Parser::Base attr_reader :file, :source # Initializes the parser. # @param [String] source The source being parsed. # @param [String] filename The file name of the file being parsed. # @return [void] def initialize(source, filename) # rubocop:disable Lint/MissingSuper @source = source @file = filename @visitor = ::Puppet::Pops::Visitor.new(self, 'transform') end # Parses the source. # @return [void] def parse begin Puppet[:tasks] = true if Puppet.settings.include?(:tasks) @statements ||= (@visitor.visit(::Puppet::Pops::Parser::Parser.new.parse_string(source)) || []).compact rescue ::Puppet::ParseError => e log.error "Failed to parse #{@file}: #{e.message}" @statements = [] end @statements.freeze self end # Gets an enumerator for the statements that were parsed. # @return Returns an enumerator for the statements that were parsed. def enumerator @statements end private # TODO: Fix the rubocop violations in this file between the following rubocop:disable/enable lines # rubocop:disable Naming/MethodName def transform_Program(o) # Cache the lines of the source text; we'll use this to locate comments @lines = o.source_text.lines.to_a o.definitions.map { |d| @visitor.visit(d) } end def transform_Factory(o) @visitor.visit(o.current) end def transform_HostClassDefinition(o) statement = PuppetStrings::Yard::Parsers::Puppet::ClassStatement.new(o, @file) statement.extract_docstring(@lines) statement end def transform_ResourceTypeDefinition(o) statement = PuppetStrings::Yard::Parsers::Puppet::DefinedTypeStatement.new(o, @file) statement.extract_docstring(@lines) statement end def transform_FunctionDefinition(o) statement = PuppetStrings::Yard::Parsers::Puppet::FunctionStatement.new(o, @file) statement.extract_docstring(@lines) statement end def transform_PlanDefinition(o) statement = PuppetStrings::Yard::Parsers::Puppet::PlanStatement.new(o, @file) statement.extract_docstring(@lines) statement end def transform_TypeAlias(o) statement = PuppetStrings::Yard::Parsers::Puppet::DataTypeAliasStatement.new(o, @file) statement.extract_docstring(@lines) statement end def transform_Object(o) # Ignore anything else (will be compacted out of the resulting array) end # rubocop:enable Naming/MethodName end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/parsers/puppet/statement.rb000066400000000000000000000137361466634474300313720ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet' require 'puppet/pops' module PuppetStrings::Yard::Parsers::Puppet # Represents the base Puppet language statement. class Statement # The pattern for parsing docstring comments. COMMENT_REGEX = /^\s*#+\s?/.freeze attr_reader :source, :file, :line, :docstring, :comments_range # Initializes the Puppet language statement. # @param object The Puppet parser model object for the statement. # @param [String] file The file name of the file containing the statement. def initialize(object, file) @file = file @source = PuppetStrings::Yard::Util.ast_to_text(object) @line = object.line @comments_range = nil end # Extracts the docstring for the statement given the source lines. # @param [Array] lines The source lines for the file containing the statement. # @return [void] def extract_docstring(lines) comment = [] (0..@line - 2).reverse_each do |index| break unless index <= lines.count line = lines[index].strip count = line.size line.gsub!(COMMENT_REGEX, '') # Break out if nothing was removed (wasn't a comment line) break unless line.size < count comment << line end @comments_range = (@line - comment.size - 1..@line - 1) @docstring = YARD::Docstring.new(comment.reverse.join("\n")) end # Shows the first line context for the statement. # @return [String] Returns the first line context for the statement. def show "\t#{@line}: #{first_line}" end # Gets the full comments of the statement. # @return [String] Returns the full comments of the statement. def comments @docstring.all end # Determines if the comments have hash flag. # @return [Boolean] Returns true if the comments have a hash flag or false if not. def comments_hash_flag false end private def first_line @source.split(/\r?\n/).first.strip end end # Implements a parameterized statement (a statement that takes parameters). class ParameterizedStatement < Statement # Implements a parameter for a parameterized statement. class Parameter attr_reader :name, :type, :value # Initializes the parameter. # @param [Puppet::Pops::Model::Parameter] parameter The parameter model object. def initialize(parameter) @name = parameter.name # Take the exact text for the type expression @type = PuppetStrings::Yard::Util.ast_to_text(parameter.type_expr) if parameter.type_expr # Take the exact text for the default value expression return unless parameter.value @value = PuppetStrings::Yard::Util.ast_to_text(parameter.value) end end attr_reader :parameters # Initializes the parameterized statement. # @param object The Puppet parser model object that has parameters. # @param [String] file The file containing the statement. def initialize(object, file) super @parameters = object.parameters.map { |parameter| Parameter.new(parameter) } end end # Implements the Puppet class statement. class ClassStatement < ParameterizedStatement attr_reader :name, :parent_class # Initializes the Puppet class statement. # @param [Puppet::Pops::Model::HostClassDefinition] object The model object for the class statement. # @param [String] file The file containing the statement. def initialize(object, file) super @name = object.name @parent_class = object.parent_class end end # Implements the Puppet defined type statement. class DefinedTypeStatement < ParameterizedStatement attr_reader :name # Initializes the Puppet defined type statement. # @param [Puppet::Pops::Model::ResourceTypeDefinition] object The model object for the defined type statement. # @param [String] file The file containing the statement. def initialize(object, file) super @name = object.name end end # Implements the Puppet function statement. class FunctionStatement < ParameterizedStatement attr_reader :name, :type # Initializes the Puppet function statement. # @param [Puppet::Pops::Model::FunctionDefinition] object The model object for the function statement. # @param [String] file The file containing the statement. def initialize(object, file) super @name = object.name return unless object.respond_to? :return_type type = object.return_type return unless type @type = PuppetStrings::Yard::Util.ast_to_text(type).gsub('>> ', '') end end # Implements the Puppet plan statement. class PlanStatement < ParameterizedStatement attr_reader :name # Initializes the Puppet plan statement. # @param [Puppet::Pops::Model::PlanDefinition] object The model object for the plan statement. # @param [String] file The file containing the statement. def initialize(object, file) super @name = object.name end end # Implements the Puppet data type alias statement. class DataTypeAliasStatement < Statement attr_reader :name, :alias_of # Initializes the Puppet data type alias statement. # @param [Puppet::Pops::Model::TypeAlias] object The model object for the type statement. # @param [String] file The file containing the statement. def initialize(object, file) super type_expr = object.type_expr case type_expr when Puppet::Pops::Model::AccessExpression # TODO: I don't like rebuilding the source from the AST, but AccessExpressions don't expose the original source @alias_of = +"#{PuppetStrings::Yard::Util.ast_to_text(type_expr.left_expr)}[" # alias_of should be mutable so we add a + to the string. @alias_of << type_expr.keys.map { |key| PuppetStrings::Yard::Util.ast_to_text(key) }.join(', ') @alias_of << ']' else @alias_of = PuppetStrings::Yard::Util.ast_to_text(type_expr) end @name = object.name end end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/tags.rb000066400000000000000000000006261466634474300253220ustar00rootroot00000000000000# frozen_string_literal: true # The module for custom YARD tags. module PuppetStrings::Yard::Tags require 'puppet-strings/yard/tags/factory' require 'puppet-strings/yard/tags/parameter_directive' require 'puppet-strings/yard/tags/property_directive' require 'puppet-strings/yard/tags/overload_tag' require 'puppet-strings/yard/tags/summary_tag' require 'puppet-strings/yard/tags/enum_tag' end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/tags/000077500000000000000000000000001466634474300247715ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/tags/enum_tag.rb000066400000000000000000000006361466634474300271220ustar00rootroot00000000000000# frozen_string_literal: true require 'yard/tags/option_tag' # Implements an enum tag for describing enumerated value data types class PuppetStrings::Yard::Tags::EnumTag < YARD::Tags::OptionTag # Registers the tag with YARD. # @return [void] def self.register! YARD::Tags::Library.define_tag('puppet.enum', :enum, :with_enums) YARD::Tags::Library.visible_tags.place(:enum).after(:option) end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/tags/factory.rb000066400000000000000000000013371466634474300267710ustar00rootroot00000000000000# frozen_string_literal: true require 'yard/tags/default_factory' require 'puppet-strings/yard/tags/enum_tag' # Factory for creating tags. class PuppetStrings::Yard::Tags::Factory < YARD::Tags::DefaultFactory # Parses tag text and creates a new enum tag type. Modeled after # the parse_tag_with_options method in YARD::Tags::DefaultFactory. # # @param tag_name the name of the tag to parse # @param [String] text the raw tag text # @return [Tag] a tag object with the tag_name, name, and nested Tag as type def parse_tag_with_enums(tag_name, text) name, text = *extract_name_from_text(text) PuppetStrings::Yard::Tags::EnumTag.new(tag_name, name, parse_tag_with_name(tag_name, text)) end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/tags/overload_tag.rb000066400000000000000000000077171466634474300300000ustar00rootroot00000000000000# frozen_string_literal: true # Implements an overload tag for Puppet functions # # This differs from Yard's overload tag in that the signatures are formatted according to Puppet language rules. class PuppetStrings::Yard::Tags::OverloadTag < YARD::Tags::Tag attr_reader :parameters, :docstring # Initializes the overload tag. # @param [String, Symbol] name The name of the function being overloaded. # @param [String] docstring The docstring for the overload. # @return [void] def initialize(name, docstring) super(:overload, nil) @name = name.to_s @parameters = [] @docstring = YARD::Docstring.new(docstring) end # Gets the signature of the overload. # @return [String] Returns the signature of the overload. def signature tags = self.tags(:param) args = @parameters.map do |parameter| name, default = parameter tag = tags.find { |t| t.name == name } if tags type = tag&.types ? "#{tag.type} " : 'Any ' prefix = (name[0]).to_s if name.start_with?('*', '&') name = name[1..] if prefix default = " = #{default}" if default "#{type}#{prefix}$#{name}#{default}" end.join(', ') "#{@name}(#{args})" end # Adds a tag to the overload's docstring. # @param [YARD::Tag] tag The tag to add to the overload's docstring. # @return [void] def add_tag(tag) @docstring.add_tag(tag) end # Gets the first tag of the given name. # @param [String, Symbol] name The name of the tag. # @return [YARD::Tag] Returns the first tag if found or nil if not found. def tag(name) @docstring.tag(name) end # Gets all tags or tags of a given name. # @param [String, Symbol] name The name of the tag to get or nil for all tags. # @return [Array] Returns an array of tags. def tags(name = nil) @docstring.tags(name) end # Determines if a tag with the given name is present. # @param [String, Symbol] name The tag name. # @return [Boolean] Returns true if there is at least one tag with the given name or false if not. def has_tag?(name) # rubocop:disable Naming/PredicateName @docstring.has_tag?(name) end # Sets the object associated with this tag. # @param [Object] value The object to associate with this tag. # @return [void] def object=(value) super @docstring.object = value @docstring.tags.each { |tag| tag.object = value } end # Responsible for forwarding method calls to the associated object. # @param [Symbol] method_name The method being invoked. # @param [Array] args The args passed to the method. # @param block The block passed to the method. # @return Returns what the method call on the object would return. def method_missing(method_name, *args, &block) return object.send(method_name, *args, &block) if object.respond_to? method_name super end # Determines if the associated object responds to the give missing method name. # @param [Symbol, String] method_name The name of the method to check. # @param [Boolean] include_all True to include all methods in the check or false for only public methods. # @return [Boolean] Returns true if the object responds to the method or false if not. def respond_to_missing?(method_name, include_all = false) object.respond_to?(method_name, include_all) || super end # Gets the type of the object associated with this tag. # @return [Symbol] Returns the type of the object associated with this tag. def type object.type end # Converts the overload tag to a hash representation. # @return [Hash] Returns a hash representation of the overload. def to_hash hash = {} hash[:tag_name] = tag_name hash[:text] = text if text hash[:signature] = signature hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring) unless docstring.blank? defaults = Hash[*parameters.reject { |p| p[1].nil? }.flatten] hash[:defaults] = defaults unless defaults.empty? hash[:types] = types if types hash[:name] = name if name hash end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/tags/parameter_directive.rb000066400000000000000000000014241466634474300313350ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/code_objects' # Implements a parameter directive (e.g. #@!puppet.type.param) for documenting Puppet resource types. class PuppetStrings::Yard::Tags::ParameterDirective < YARD::Tags::Directive # Called to invoke the directive. # @return [void] def call return unless object.respond_to?(:add_parameter) # Add a parameter to the resource parameter = PuppetStrings::Yard::CodeObjects::Type::Parameter.new(tag.name, tag.text) tag.types&.each do |value| parameter.add(value) end object.add_parameter parameter end # Registers the directive with YARD. # @return [void] def self.register! YARD::Tags::Library.define_directive('puppet.type.param', :with_types_and_name, self) end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/tags/property_directive.rb000066400000000000000000000014221466634474300312370ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet-strings/yard/code_objects' # Implements a parameter directive (e.g. #@!puppet.type.property) for documenting Puppet resource types. class PuppetStrings::Yard::Tags::PropertyDirective < YARD::Tags::Directive # Called to invoke the directive. # @return [void] def call return unless object.respond_to?(:add_property) # Add a property to the resource property = PuppetStrings::Yard::CodeObjects::Type::Property.new(tag.name, tag.text) tag.types&.each do |value| property.add(value) end object.add_property property end # Registers the directive with YARD. # @return [void] def self.register! YARD::Tags::Library.define_directive('puppet.type.property', :with_types_and_name, self) end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/tags/summary_tag.rb000066400000000000000000000004611466634474300276470ustar00rootroot00000000000000# frozen_string_literal: true # Implements a summary tag for general purpose short descriptions class PuppetStrings::Yard::Tags::SummaryTag < YARD::Tags::Tag # Registers the tag with YARD. # @return [void] def self.register! YARD::Tags::Library.define_tag('puppet.summary', :summary) end end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/000077500000000000000000000000001466634474300260315ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/000077500000000000000000000000001466634474300274555ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/fulldoc/000077500000000000000000000000001466634474300311055ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/fulldoc/html/000077500000000000000000000000001466634474300320515ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/fulldoc/html/css/000077500000000000000000000000001466634474300326415ustar00rootroot00000000000000common.css000066400000000000000000000002061466634474300345620ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/fulldoc/html/css/* Ensure the search bar doesn't overlap with links */ .fixed_header { padding-bottom: 25px; } #full_list { padding-top: 15px; } full_list_puppet_class.erb000066400000000000000000000003721466634474300372450ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/fulldoc/html<% even = false %> <% @items.each do |item| %>
  • <%= linkify item, h(item.name(true)) %>
  • <% even = !even %> <% end %> full_list_puppet_data_type.erb000066400000000000000000000005161466634474300401120ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/fulldoc/html<% even = false %> <% @items.each do |item| %>
  • <%= linkify item, h(item.name(false)) %> <% if item.type == :puppet_data_type_alias %>Alias<% end %>
  • <% even = !even %> <% end %> full_list_puppet_defined_type.erb000066400000000000000000000003721466634474300405770ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/fulldoc/html<% even = false %> <% @items.each do |item| %>
  • <%= linkify item, h(item.name(true)) %>
  • <% even = !even %> <% end %> full_list_puppet_function.erb000066400000000000000000000004541466634474300377660ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/fulldoc/html<% even = false %> <% @items.each do |item| %>
  • <%= linkify item, h(item.name(false)) %> <%= item.function_type %>
  • <% even = !even %> <% end %> full_list_puppet_plan.erb000066400000000000000000000003721466634474300370720ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/fulldoc/html<% even = false %> <% @items.each do |item| %>
  • <%= linkify item, h(item.name(true)) %>
  • <% even = !even %> <% end %> full_list_puppet_provider.erb000066400000000000000000000004751466634474300377760ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/fulldoc/html<% even = false %> <% @items.each do |item| %>
  • <%= linkify item, h(item.name(true)) %> Resource type: <%=item.type_name%>
  • <% even = !even %> <% end %> full_list_puppet_task.erb000066400000000000000000000003721466634474300371020ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/fulldoc/html<% even = false %> <% @items.each do |item| %>
  • <%= linkify item, h(item.name(true)) %>
  • <% even = !even %> <% end %> full_list_puppet_type.erb000066400000000000000000000003721466634474300371210ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/fulldoc/html<% even = false %> <% @items.each do |item| %>
  • <%= linkify item, h(item.name(true)) %>
  • <% even = !even %> <% end %> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/fulldoc/html/setup.rb000066400000000000000000000053101466634474300335350ustar00rootroot00000000000000# frozen_string_literal: true # Generates the searchable Puppet class list. # @return [void] def generate_puppet_class_list @items = Registry.all(:puppet_class).sort_by { |c| c.name.to_s } @list_title = 'Puppet Class List' @list_type = 'puppet_class' generate_list_contents end # Generates the searchable Puppet data type list. # @return [void] def generate_puppet_data_type_list @items = Registry.all(:puppet_data_type, :puppet_data_type_alias).sort_by { |dt| dt.name.to_s } @list_title = 'Data Type List' @list_type = 'puppet_data_type' generate_list_contents end # Generates the searchable Puppet defined type list. # @return [void] def generate_puppet_defined_type_list @items = Registry.all(:puppet_defined_type).sort_by { |dt| dt.name.to_s } @list_title = 'Defined Type List' @list_type = 'puppet_defined_type' generate_list_contents end # Generates the searchable Puppet resource type list. # @return [void] def generate_puppet_type_list @items = Registry.all(:puppet_type).sort_by { |t| t.name.to_s } @list_title = 'Resource Type List' @list_type = 'puppet_type' generate_list_contents end # Generates the searchable Puppet provider list. # @return [void] def generate_puppet_provider_list @items = Registry.all(:puppet_provider).sort_by { |p| p.name.to_s } @list_title = 'Provider List' @list_type = 'puppet_provider' generate_list_contents end # Generates the searchable Puppet function list. # @return [void] def generate_puppet_function_list @items = Registry.all(:puppet_function).sort_by { |f| f.name.to_s } @list_title = 'Puppet Function List' @list_type = 'puppet_function' generate_list_contents end # Generates the searchable Ruby method list. # @return [void] def generate_method_list @items = prune_method_listing(Registry.all(:method), false) @items = @items.reject { |m| m.name.to_s =~ /=$/ && m.is_attribute? } @items = @items.sort_by { |m| m.name.to_s } @list_title = 'Ruby Method List' @list_type = 'method' generate_list_contents end # Generate a searchable Ruby class list in the output. # @return [void] def generate_class_list @items = options.objects if options.objects @list_title = 'Ruby Class List' @list_type = 'class' generate_list_contents end # Generates the searchable Puppet Task list. # @return [void] def generate_puppet_task_list @items = Registry.all(:puppet_task).sort_by { |t| t.name.to_s } @list_title = 'Puppet Task List' @list_type = 'puppet_task' generate_list_contents end # Generates the searchable Puppet Plan list. # @return [void] def generate_puppet_plan_list @items = Registry.all(:puppet_plan).sort_by { |t| t.name.to_s } @list_title = 'Puppet Plan List' @list_type = 'puppet_plan' generate_list_contents end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/layout/000077500000000000000000000000001466634474300307725ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/layout/html/000077500000000000000000000000001466634474300317365ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/layout/html/footer.erb000066400000000000000000000002111466634474300337200ustar00rootroot00000000000000 puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/layout/html/objects.erb000066400000000000000000000020601466634474300340570ustar00rootroot00000000000000<% unless @objects_by_letter.empty? %>

    <%= @title %>

    <% i = 0 %>
    <% @objects_by_letter.sort_by {|l,o| l.to_s }.each do |letter, objects| %> <% if (i += 1) % 8 == 0 %> <% i = 0 %> <% end %>
    • <%= letter %>
      • <% objects.each do |obj| %>
      • <%= linkify obj, obj.name %> <% if (obj.type == :module || obj.type == :class) && !obj.namespace.root? %> (<%= obj.namespace.path %>) <% elsif obj.type == :puppet_provider %> (Resource type: <%= obj.type_name %>) <% elsif obj.type == :puppet_function %> (<%= obj.function_type %>) <% elsif obj.type == :puppet_data_type_alias %> (Alias) <% end %>
      • <% end %>
    <% end %>
    <% end %> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/layout/html/setup.rb000066400000000000000000000143521466634474300334300ustar00rootroot00000000000000# frozen_string_literal: true # Initializes the template. # @return [void] def init case object when '_index.html' @page_title = options.title sections :layout, [:index, [:listing, %i[classes data_types defined_types types providers functions tasks plans files objects]]] else super end end # Renders the layout section. # @return [String] Returns the rendered section. def layout @nav_url = url_for_list(!@file || options.index ? menu_lists.first[:type] : 'file') case object when nil, String @path = nil when @file @path = @file.path when !object.is_a?(YARD::CodeObjects::NamespaceObject) @path = object.parent.path @nav_url = url_for_list('class') when YARD::CodeObjects::ClassObject @path = object.path @nav_url = url_for_list('class') when PuppetStrings::Yard::CodeObjects::Class @nav_url = url_for_list('puppet_class') @page_title = "Puppet Class: #{object.name}" @path = object.path when PuppetStrings::Yard::CodeObjects::DataType, PuppetStrings::Yard::CodeObjects::DataTypeAlias @nav_url = url_for_list('puppet_data_type') @page_title = "Data Type: #{object.name}" @path = object.path when PuppetStrings::Yard::CodeObjects::DefinedType @nav_url = url_for_list('puppet_defined_type') @page_title = "Defined Type: #{object.name}" @path = object.path when PuppetStrings::Yard::CodeObjects::Type @nav_url = url_for_list('puppet_type') @page_title = "Resource Type: #{object.name}" @path = object.path when PuppetStrings::Yard::CodeObjects::Provider @nav_url = url_for_list('puppet_provider') @page_title = "Provider: #{object.name}" @path = object.path when PuppetStrings::Yard::CodeObjects::Function @nav_url = url_for_list('puppet_function') @page_title = "Puppet Function: #{object.name} (#{object.function_type})" @path = object.path when PuppetStrings::Yard::CodeObjects::Task @nav_url = url_for_list('puppet_task') @page_title = "Puppet Task: #{object.name}" @path = object.path when PuppetStrings::Yard::CodeObjects::Plan @nav_url = url_for_list('puppet_plan') @page_title = "Puppet Plan: #{object.name}" @path = object.path else @path = object.path end final_layout = erb(:layout) PuppetStrings::Yard::Util.github_to_yard_links(final_layout) if @file && @file.name == 'README' final_layout end # Creates the dynamic menu lists. # @return [Array] Returns the dynamic menu list. def create_menu_lists menu_lists = [ { type: 'puppet_class', title: 'Puppet Classes', search_title: 'Puppet Classes' }, { type: 'puppet_data_type', title: 'Data Types', search_title: 'Data Types' }, { type: 'puppet_defined_type', title: 'Defined Types', search_title: 'Defined Types' }, { type: 'puppet_type', title: 'Resource Types', search_title: 'Resource Types' }, { type: 'puppet_provider', title: 'Providers', search_title: 'Providers' }, { type: 'puppet_function', title: 'Puppet Functions', search_title: 'Puppet Functions' }, { type: 'puppet_task', title: 'Puppet Tasks', search_totle: 'Puppet Tasks' }, { type: 'puppet_plan', title: 'Puppet Plans', search_totle: 'Puppet Plans' }, { type: 'class', title: 'Ruby Classes', search_title: 'Class List' }, { type: 'method', title: 'Ruby Methods', search_title: 'Method List' } ] menu_lists.delete_if { |e| YARD::Registry.all(e[:type].intern).empty? } # We must always return at least one group, so always keep the files list if menu_lists.empty? || !YARD::Registry.all(:file).empty? menu_lists << { type: 'file', title: 'Files', search_title: 'File List' } end menu_lists end # Gets the menu lists to use. # @return [Array <% if object.statement.parent_class %>
    Inherits:
    <%= linkify(Registry["puppet_classes::#{object.statement.parent_class}"], object.statement.parent_class.dup) %>
    <% end %> <% if @subclasses && !@subclasses.empty? %>
    Inherited by:
    <% @subclasses.each do |subclass| %> <%= linkify(subclass, subclass.name.to_s) %>
    <% end %>
    <% end %>
    Defined in:
    <%= object.file %><% if object.files.size > 1 %>,
    <%= object.files[1..-1].map {|f| f.first }.join(",
    ") %> <% end %>
    deprecated.erb000077500000000000000000000002511466634474300356370ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_class/html<% object.tags(:deprecated).each do |tag| %>
    DEPRECATED: <%= htmlify_line deprecated.text %>
    <% end %> header.erb000066400000000000000000000000521466634474300347630ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_class/html

    Puppet Class: <%= object.name %>

    note.erb000077500000000000000000000002231466634474300345030ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_class/html<% object.tags(:note).each do |tag| %>
    Note: <%= htmlify_line tag.text %>
    <% end %> overview.erb000066400000000000000000000001721466634474300354040ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_class/html

    Overview

    <%= htmlify(object.docstring) %>
    setup.rb000066400000000000000000000006421466634474300345330ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_class/html# frozen_string_literal: true # Initializes the template. # @return [void] def init sections :header, :box_info, :summary, :overview, :note, :todo, :deprecated, T('tags'), :source end # Renders the box_info section. # @return [String] Returns the rendered section. def box_info @subclasses = Registry.all(:puppet_class).find_all do |c| c.statement.parent_class == object.name.to_s end erb(:box_info) end source.erb000066400000000000000000000006531466634474300350420ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_class/html
    <%= "\n\n\n" %><%= h format_lines(object) %>
    # File '<%= h object.file %>'<% if object.line %>, line <%= object.line %><% end %><%= "\n\n" %><%= html_syntax_highlight object.source %>
    summary.erb000066400000000000000000000001671466634474300352370ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_class/html<% if object.docstring.has_tag?(:summary) %>

    Summary

    <%= object.docstring.tag(:summary).text %> <% end %> todo.erb000077500000000000000000000002201466634474300345000ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_class/html<% object.tags(:todo).each do |tag| %>
    TODO: <%= htmlify_line tag.text %>
    <% end %> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type/000077500000000000000000000000001466634474300330245ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type/html/000077500000000000000000000000001466634474300337705ustar00rootroot00000000000000box_info.erb000066400000000000000000000004101466634474300362010ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type/html
    Defined in:
    <%= object.file %><% if object.files.size > 1 %>,
    <%= object.files[1..-1].map {|f| f.first }.join(",
    ") %>
    <% end %> deprecated.erb000077500000000000000000000002511466634474300365040ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type/html<% object.tags(:deprecated).each do |tag| %>
    DEPRECATED: <%= htmlify_line deprecated.text %>
    <% end %> header.erb000066400000000000000000000000561466634474300356340ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type/html

    Puppet Data Type: <%= object.name %>

    method_details_list.erb000066400000000000000000000003521466634474300404230ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type/html

    Data Type Functions

    <% method_listing.each_with_index do |meth, i| %>

    <%= meth.name %>

    <%= yieldall :object => meth, :owner => object, :index => i %>
    <% end %> note.erb000066400000000000000000000002231466634474300353450ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type/html<% object.tags(:note).each do |tag| %>
    Note: <%= htmlify_line tag.text %>
    <% end %> overview.erb000066400000000000000000000001721466634474300362510ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type/html

    Overview

    <%= htmlify(object.docstring) %>
    setup.rb000066400000000000000000000005711466634474300354010ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type/html# frozen_string_literal: true # Initializes the template. # @return [void] def init sections :header, :box_info, :summary, :overview, :note, :todo, :deprecated, T('tags'), :method_details_list, [T('method_details')], :source end def method_listing sort_listing(object.functions) end def sort_listing(list) list.sort_by { |o| [o.scope.to_s, o.name.to_s.downcase] } end source.erb000066400000000000000000000006531466634474300357070ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type/html
    <%= "\n\n\n" %><%= h format_lines(object) %>
    # File '<%= h object.file %>'<% if object.line %>, line <%= object.line %><% end %><%= "\n\n" %><%= html_syntax_highlight object.source %>
    summary.erb000066400000000000000000000001671466634474300361040ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type/html<% if object.docstring.has_tag?(:summary) %>

    Summary

    <%= object.docstring.tag(:summary).text %> <% end %> todo.erb000066400000000000000000000002201466634474300353420ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type/html<% object.tags(:todo).each do |tag| %>
    TODO: <%= htmlify_line tag.text %>
    <% end %> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/000077500000000000000000000000001466634474300341755ustar00rootroot00000000000000html/000077500000000000000000000000001466634474300350625ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type_aliasalias_of.erb000066400000000000000000000004151466634474300373310ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html<% if @alias_of && !@alias_of.empty? %>

    <%= @tag_title %>

    <%= @alias_of %>
    <% end %> box_info.erb000066400000000000000000000004101466634474300373520ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html
    Defined in:
    <%= object.file %><% if object.files.size > 1 %>,
    <%= object.files[1..-1].map {|f| f.first }.join(",
    ") %>
    <% end %> deprecated.erb000077500000000000000000000002511466634474300376550ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html<% object.tags(:deprecated).each do |tag| %>
    DEPRECATED: <%= htmlify_line deprecated.text %>
    <% end %> header.erb000066400000000000000000000000641466634474300370040ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html

    Puppet Data Type Alias: <%= object.name %>

    note.erb000066400000000000000000000002231466634474300365160ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html<% object.tags(:note).each do |tag| %>
    Note: <%= htmlify_line tag.text %>
    <% end %> overview.erb000066400000000000000000000001721466634474300374220ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html

    Overview

    <%= htmlify(object.docstring) %>
    setup.rb000066400000000000000000000011441466634474300365470ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html# frozen_string_literal: true # Initializes the template. # @return [void] def init sections :header, :box_info, :summary, :overview, :alias_of, :note, :todo, :deprecated, T('tags'), :source end # Renders the alias_of section. # @return [String] Returns the rendered section. def alias_of # Properties are the same thing as parameters (from the documentation standpoint), # so reuse the same template but with a different title and data source. # @parameters = object.properties || [] # @parameters.sort_by! { |p| p.name } @tag_title = 'Alias of' @alias_of = object.alias_of erb(:alias_of) end source.erb000066400000000000000000000006531466634474300370600ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html
    <%= "\n\n\n" %><%= h format_lines(object) %>
    # File '<%= h object.file %>'<% if object.line %>, line <%= object.line %><% end %><%= "\n\n" %><%= html_syntax_highlight object.source %>
    summary.erb000066400000000000000000000001671466634474300372550ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html<% if object.docstring.has_tag?(:summary) %>

    Summary

    <%= object.docstring.tag(:summary).text %> <% end %> todo.erb000066400000000000000000000002201466634474300365130ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html<% object.tags(:todo).each do |tag| %>
    TODO: <%= htmlify_line tag.text %>
    <% end %> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_defined_type/000077500000000000000000000000001466634474300335115ustar00rootroot00000000000000html/000077500000000000000000000000001466634474300343765ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_defined_typebox_info.erb000066400000000000000000000004101466634474300366660ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_defined_type/html
    Defined in:
    <%= object.file %><% if object.files.size > 1 %>,
    <%= object.files[1..-1].map {|f| f.first }.join(",
    ") %>
    <% end %> deprecated.erb000077500000000000000000000002511466634474300371710ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_defined_type/html<% object.tags(:deprecated).each do |tag| %>
    DEPRECATED: <%= htmlify_line deprecated.text %>
    <% end %> header.erb000066400000000000000000000000521466634474300363150ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_defined_type/html

    Defined Type: <%= object.name %>

    note.erb000077500000000000000000000002231466634474300360350ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_defined_type/html<% object.tags(:note).each do |tag| %>
    Note: <%= htmlify_line tag.text %>
    <% end %> overview.erb000066400000000000000000000001721466634474300367360ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_defined_type/html

    Overview

    <%= htmlify(object.docstring) %>
    setup.rb000066400000000000000000000002731466634474300360650ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_defined_type/html# frozen_string_literal: true # Initializes the template. # @return [void] def init sections :header, :box_info, :summary, :overview, :note, :todo, :deprecated, T('tags'), :source end source.erb000066400000000000000000000006531466634474300363740ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_defined_type/html
    <%= "\n\n\n" %><%= h format_lines(object) %>
    # File '<%= h object.file %>'<% if object.line %>, line <%= object.line %><% end %><%= "\n\n" %><%= html_syntax_highlight object.source %>
    summary.erb000066400000000000000000000001671466634474300365710ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_defined_type/html<% if object.docstring.has_tag?(:summary) %>

    Summary

    <%= object.docstring.tag(:summary).text %> <% end %> todo.erb000077500000000000000000000002201466634474300360320ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_defined_type/html<% object.tags(:todo).each do |tag| %>
    TODO: <%= htmlify_line tag.text %>
    <% end %> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_function/000077500000000000000000000000001466634474300326775ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_function/html/000077500000000000000000000000001466634474300336435ustar00rootroot00000000000000box_info.erb000066400000000000000000000005341466634474300360630ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_function/html
    Defined in:
    <%= object.file %><% if object.files.size > 1 %>,
    <%= object.files[1..-1].map {|f| f.first }.join(",
    ") %>
    <% end %>
    Function type:
    <%= object.function_type %>
    deprecated.erb000077500000000000000000000002511466634474300363570ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_function/html<% object.tags(:deprecated).each do |tag| %>
    DEPRECATED: <%= htmlify_line deprecated.text %>
    <% end %> header.erb000066400000000000000000000000551466634474300355060ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_function/html

    Puppet Function: <%= object.name %>

    note.erb000077500000000000000000000002231466634474300352230ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_function/html<% object.tags(:note).each do |tag| %>
    Note: <%= htmlify_line tag.text %>
    <% end %> overview.erb000066400000000000000000000010461466634474300361250ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_function/html

    Overview

    <% unless object.has_tag? :overload %>
    <%= "#{h(object.signature)} ⇒ #{signature_types(object, false)}" %>
    <% end %>
    <%= htmlify(object.docstring) %>
    <%= yieldall %>
    setup.rb000066400000000000000000000002751466634474300352550ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_function/html# frozen_string_literal: true # Initializes the template. # @return [void] def init sections :header, :box_info, :summary, :overview, [:note, :todo, :deprecated, T('tags'), :source] end source.erb000066400000000000000000000006531466634474300355620ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_function/html
    <%= "\n\n\n" %><%= h format_lines(object) %>
    # File '<%= h object.file %>'<% if object.line %>, line <%= object.line %><% end %><%= "\n\n" %><%= html_syntax_highlight object.source %>
    summary.erb000066400000000000000000000001671466634474300357570ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_function/html<% if object.docstring.has_tag?(:summary) %>

    Summary

    <%= object.docstring.tag(:summary).text %> <% end %> todo.erb000077500000000000000000000002201466634474300352200ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_function/html<% object.tags(:todo).each do |tag| %>
    TODO: <%= htmlify_line tag.text %>
    <% end %> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_plan/000077500000000000000000000000001466634474300320045ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_plan/html/000077500000000000000000000000001466634474300327505ustar00rootroot00000000000000box_info.erb000066400000000000000000000004101466634474300351610ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_plan/html
    Defined in:
    <%= object.file %><% if object.files.size > 1 %>,
    <%= object.files[1..-1].map {|f| f.first }.join(",
    ") %>
    <% end %> deprecated.erb000077500000000000000000000002511466634474300354640ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_plan/html<% object.tags(:deprecated).each do |tag| %>
    DEPRECATED: <%= htmlify_line deprecated.text %>
    <% end %> header.erb000066400000000000000000000000511466634474300346070ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_plan/html

    Puppet Plan: <%= object.name %>

    note.erb000077500000000000000000000002231466634474300343300ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_plan/html<% object.tags(:note).each do |tag| %>
    Note: <%= htmlify_line tag.text %>
    <% end %> overview.erb000066400000000000000000000001721466634474300352310ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_plan/html

    Overview

    <%= htmlify(object.docstring) %>
    setup.rb000066400000000000000000000004571466634474300343640ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_plan/html# frozen_string_literal: true # Initializes the template. # @return [void] def init sections :header, :box_info, :summary, :overview, :note, :todo, :deprecated, T('tags'), :source end # Renders the box_info section. # @return [String] Returns the rendered section. def box_info erb(:box_info) end source.erb000066400000000000000000000006531466634474300346670ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_plan/html
    <%= "\n\n\n" %><%= h format_lines(object) %>
    # File '<%= h object.file %>'<% if object.line %>, line <%= object.line %><% end %><%= "\n\n" %><%= html_syntax_highlight object.source %>
    summary.erb000066400000000000000000000001671466634474300350640ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_plan/html<% if object.docstring.has_tag?(:summary) %>

    Summary

    <%= object.docstring.tag(:summary).text %> <% end %> todo.erb000077500000000000000000000002201466634474300343250ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_plan/html<% object.tags(:todo).each do |tag| %>
    TODO: <%= htmlify_line tag.text %>
    <% end %> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_provider/000077500000000000000000000000001466634474300327045ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_provider/html/000077500000000000000000000000001466634474300336505ustar00rootroot00000000000000box_info.erb000066400000000000000000000006201466634474300360640ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_provider/html
    Defined in:
    <%= object.file %><% if object.files.size > 1 %>,
    <%= object.files[1..-1].map {|f| f.first }.join(",
    ") %>
    <% end %>
    Resource type:
    <%= linkify(Registry["puppet_types::#{object.type_name}"], object.type_name) %>
    collection.erb000066400000000000000000000007221466634474300364170ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_provider/html<% if @collection && !@collection.empty? %>

    <%= @title %>

      <% if @collection.is_a?(Hash) %> <% @collection.each do |key, value| %>
    • <%= key %> — <%= value %>
    • <% end %> <% elsif @collection.is_a?(Array) %> <% @collection.each do |kvps| %>
    • <%= kvps.map{|k,v| "#{k} — #{v}"}.join(', ') %>
    • <% end %> <% end %>
    <% end %> features.erb000066400000000000000000000004071466634474300361020ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_provider/html<% if object.features && !object.features.empty? %>

    Features

      <% object.features.each do |feature| %>
    • <%= feature %>
    • <% end %>
    <% end %> header.erb000066400000000000000000000000461466634474300355130ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_provider/html

    Provider: <%= object.name %>

    overview.erb000066400000000000000000000001721466634474300361310ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_provider/html

    Overview

    <%= htmlify(object.docstring) %>
    setup.rb000066400000000000000000000013231466634474300352550ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_provider/html# frozen_string_literal: true # Initializes the template. # @return [void] def init sections :header, :box_info, :summary, :overview, T('tags'), :features, :confines, :defaults, :commands end # Renders the confines section. # @return [String] Returns the rendered section. def confines @title = 'Confines' @collection = object.confines erb(:collection) end # Renders the defaults section. # @return [String] Returns the rendered section. def defaults @title = 'Default Provider For' @collection = object.defaults erb(:collection) end # Renders the commands section. # @return [String] Returns the rendered section. def commands @title = 'Commands' @collection = object.commands erb(:collection) end summary.erb000066400000000000000000000001671466634474300357640ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_provider/html<% if object.docstring.has_tag?(:summary) %>

    Summary

    <%= object.docstring.tag(:summary).text %> <% end %> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_task/000077500000000000000000000000001466634474300320145ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_task/html/000077500000000000000000000000001466634474300327605ustar00rootroot00000000000000box_info.erb000066400000000000000000000002571466634474300352020ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_task/html
    Defined in:
    <%= object.file %>,
    <%= object.file.gsub('json','rb') %>
    header.erb000066400000000000000000000000511466634474300346170ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_task/html

    Puppet Task: <%= object.name %>

    input.erb000066400000000000000000000002661466634474300345360ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_task/html<% if json['input_method'] || json['supports_noop'] %>

    Supports noop? <%= json['supports_noop'] ? "true" : "false" %>

    <% end %> overview.erb000066400000000000000000000001541466634474300352410ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_task/html

    Overview

    <%= description %>
    parameters.erb000066400000000000000000000007001466634474300355330ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_task/html<% if @parameters && !@parameters.empty? %>

    <%= @tag_title %>

      <% @parameters.each do |parameter, values| %>
    • <%= parameter %> (<%= values['type'] %>) <% if values['description'] %> — <%= values['description'] %><% end %>
    • <% end %>
    <% end %> setup.rb000066400000000000000000000007131466634474300343670ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_task/html# frozen_string_literal: true # Initializes the template. # @return [void] def init sections :header, :box_info, T('tags'), :overview, :input, :parameters end def json object.statement.json end def description json['description'] end # Renders the parameters section. # @return [String] Returns the rendered section. def parameters @parameters = json['parameters'] || [] @parameters.to_a.sort! @tag_title = 'Parameters' erb(:parameters) end supports_noop.erb000066400000000000000000000001461466634474300363260ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_task/html<% if json['supports_noop'] %> Supports noop? <%= json['supports_noop'] %> <% end %> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_type/000077500000000000000000000000001466634474300320335ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_type/html/000077500000000000000000000000001466634474300327775ustar00rootroot00000000000000box_info.erb000066400000000000000000000007561466634474300352250ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_type/html
    Defined in:
    <%= object.file %><% if object.files.size > 1 %>,
    <%= object.files[1..-1].map {|f| f.first }.join(",
    ") %>
    <% end %> <% if @providers && !@providers.empty? %>
    Providers:
    <% @providers.each do |provider| %> <%= linkify(provider, provider.name.to_s) %>
    <% end %>
    <% end %> deprecated.erb000077500000000000000000000002511466634474300355130ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_type/html<% object.tags(:deprecated).each do |tag| %>
    DEPRECATED: <%= htmlify_line deprecated.text %>
    <% end %> features.erb000066400000000000000000000005601466634474300352310ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_type/html<% if object.features && !object.features.empty? %>

    Features

      <% object.features.each do |feature| %>
    • <%= feature.name %> <% unless feature.docstring.empty? %> — <%= htmlify_line(feature.docstring) %><% end %>
    • <% end %>
    <% end %> header.erb000066400000000000000000000000531466634474300346400ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_type/html

    Resource Type: <%= object.name %>

    note.erb000077500000000000000000000002231466634474300343570ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_type/html<% object.tags(:note).each do |tag| %>
    Note: <%= htmlify_line tag.text %>
    <% end %> overview.erb000066400000000000000000000001721466634474300352600ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_type/html

    Overview

    <%= htmlify(object.docstring) %>
    parameters.erb000066400000000000000000000017711466634474300355630ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_type/html<% if @parameters && !@parameters.empty? %>

    <%= @tag_title %>

      <% @parameters.each do |parameter| %>
    • <%= parameter.name + (parameter.isnamevar ? ' (namevar)' : '') %> <% if parameter.default %> (defaults to: <%= parameter.default %>) <% end %> <% unless parameter.docstring.empty? %>
      <%= htmlify(parameter.docstring) %>
      <% end %> <% unless parameter.values.empty? %>
      Supported values:
        <% parameter.values.each do |value| %>
      • <% other = parameter.aliases[value] %> <%= value %><% if other %> (alias for: <%= other %>)<% end %>
      • <% end %>
      <% end %>
    • <% end %>
    <% end %> setup.rb000066400000000000000000000021461466634474300344100ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_type/html# frozen_string_literal: true # Initializes the template. # @return [void] def init sections :header, :box_info, :summary, :overview, :note, :todo, :deprecated, T('tags'), :properties, :parameters, :features end # Renders the box_info section. # @return [String] Returns the rendered section. def box_info @providers = PuppetStrings::Yard::CodeObjects::Providers.instance(object.name).children erb(:box_info) end # Renders the properties section. # @return [String] Returns the rendered section. def properties # Properties are the same thing as parameters (from the documentation standpoint), # so reuse the same template but with a different title and data source. # # "checks" such as "creates" and "onlyif" are another type of property @parameters = (object.properties || []) + (object.checks || []) @parameters.sort_by!(&:name) @tag_title = 'Properties' erb(:parameters) end # Renders the parameters section. # @return [String] Returns the rendered section. def parameters @parameters = object.parameters || [] @parameters.sort_by!(&:name) @tag_title = 'Parameters' erb(:parameters) end summary.erb000066400000000000000000000001671466634474300351130ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_type/html<% if object.docstring.has_tag?(:summary) %>

    Summary

    <%= object.docstring.tag(:summary).text %> <% end %> todo.erb000077500000000000000000000002201466634474300343540ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/puppet_type/html<% object.tags(:todo).each do |tag| %>
    TODO: <%= htmlify_line tag.text %>
    <% end %> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/tags/000077500000000000000000000000001466634474300304135ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/tags/html/000077500000000000000000000000001466634474300313575ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/tags/html/enum.erb000066400000000000000000000011201466634474300330070ustar00rootroot00000000000000<% if object.has_tag?(:enum) %> <% object.parameters.each do |param, default| %> <% tags = object.tags(:enum).select {|x| x.name.to_s == param.to_s.sub(/^\*+|:$/, '') } %> <% next if tags.empty? %>

    Enum Options (<%= param %>):

      <% for tag in tags %>
    • <%= tag.pair.name %> <% if tag.pair.text && tag.pair.text =~ /\S/ %> — <%= htmlify_line(tag.pair.text) %> <% end %>
    • <% end %>
    <% end %> <% end %> puppet_overload.erb000066400000000000000000000010211466634474300351740ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/tags/html<% if object.has_tag?(:overload) && object.tags(:overload).any? {|o| !o.docstring.blank? } %>

    Signatures:

      <% object.tags(:overload).each_with_index do |overload, index| %> <% next if overload.docstring.blank? %>
    • <%= "#{h(overload.signature)} ⇒ #{signature_types(overload, false)}" %> <%= yieldall :object => overload %>
    • <% end %>
    <% end %> puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/templates/default/tags/setup.rb000066400000000000000000000013171466634474300321020ustar00rootroot00000000000000# frozen_string_literal: true # Called to return parameter tags. # @return [Array] Returns the parameter tags if the object should have parameters. def param tag(:param) if object.type == :method || object.type == :puppet_class || object.type == :puppet_data_type || object.type == :puppet_defined_type || object.type == :puppet_function || object.type == :puppet_task || object.type == :puppet_plan end # Renders the overload section. # @return [String] Returns the rendered section. def overload erb(object.type == :puppet_function ? :puppet_overload : :overload) end # Renders the enum section. # @return [String] Returns the rendered section. def enum erb(:enum) end puppetlabs-puppet-strings-a4be216/lib/puppet-strings/yard/util.rb000066400000000000000000000063141466634474300253410ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet/util' # The module for various puppet-strings utility helpers. module PuppetStrings::Yard::Util # Trims indentation from trailing whitespace and removes ruby literal quotation # syntax `%Q{}` and `%{q}` from parsed strings. # @param [String] str The string to scrub. # @return [String] A scrubbed string. def self.scrub_string(str) match = str.match(/^%[Qq]{(.*)}$/m) return Puppet::Util::Docs.scrub(match[1]) if match Puppet::Util::Docs.scrub(str) end # hacksville, usa # YARD creates ids in the html with with the style of "label-Module+description", where the markdown # we use in the README involves the GitHub-style, which is #module-description. This takes our GitHub-style # links and converts them to reference the YARD-style ids. # @see https://github.com/octokit/octokit.rb/blob/0f13944e8dbb0210d1e266addd3335c6dc9fe36a/yard/default/layout/html/setup.rb#L5-L14 # @param [String] data HTML document to convert # @return [String] HTML document with links converted def self.github_to_yard_links(data) data.scan(/href="\#(.+)"/).each do |bad_link| data = data.gsub("=\"##{bad_link.first}\"", "=\"#label-#{bad_link.first.capitalize.tr('-', '+')}\"") end data end # Converts a list of tags into an array of hashes. # @param [Array] tags List of tags to be converted into an array of hashes. # @return [Array] Returns an array of tag hashes. def self.tags_to_hashes(tags) # Skip over the API tags that are public tags.select { |t| t.tag_name != 'api' || t.text != 'public' }.map do |t| next t.to_hash if t.respond_to?(:to_hash) tag = { tag_name: t.tag_name } # grab nested information for @option and @enum tags if tag[:tag_name] == 'option' || tag[:tag_name] == 'enum' tag[:opt_name] = t.pair.name tag[:opt_text] = t.pair.text tag[:opt_types] = t.pair.types if t.pair.types tag[:parent] = t.name end tag[:text] = t.text if t.text tag[:types] = t.types if t.types tag[:name] = t.name if t.name tag end end # Converts a YARD::Docstring (or String) to a docstring hash for JSON output. # @param [YARD::Docstring, String] docstring The docstring to convert to a hash. # @param [Array] select_tags List of tags to select. Other tags will be filtered out. # @return [Hash] Returns a hash representation of the given docstring. def self.docstring_to_hash(docstring, select_tags = nil) hash = {} hash[:text] = docstring if docstring.is_a? YARD::Docstring tags = tags_to_hashes(docstring.tags.select { |t| select_tags.nil? || select_tags.include?(t.tag_name.to_sym) }) unless tags.empty? hash[:tags] = tags # .sort_by do |tag| # sort_key = tag[:tag_name].dup # sort_key << "-#{tag[:name]}" if tag[:name] # sort_key << "-#{tag[:opt_name]}" if tag[:opt_name] # sort_key # end end end hash end # Convert Puppet AST to text. # @param [Puppet::Pops::Model::PopsObject] ast The Puppet AST to convert to text. # @return [String] Returns a string of Puppet code. def self.ast_to_text(ast) ast.locator.extract_tree_text(ast) end end puppetlabs-puppet-strings-a4be216/lib/puppet/000077500000000000000000000000001466634474300214055ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet/application/000077500000000000000000000000001466634474300237105ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet/application/strings.rb000066400000000000000000000002751466634474300257320ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet/application/face_base' # Implements the 'puppet strings' application. class Puppet::Application::Strings < Puppet::Application::FaceBase end puppetlabs-puppet-strings-a4be216/lib/puppet/face/000077500000000000000000000000001466634474300223035ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet/face/strings.rb000066400000000000000000000130721466634474300243240ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet/face' # Implements the 'puppet strings' interface. Puppet::Face.define(:strings, '0.0.1') do # rubocop:disable Metrics/BlockLength summary 'Generate Puppet documentation with YARD.' action(:generate) do default option '--format OUTPUT_FORMAT' do summary 'Designate output format, JSON or markdown.' end option '--out PATH' do summary 'Write selected format to PATH. If no path is designated, strings prints to STDOUT.' end option '--markup FORMAT' do summary "The markup format to use for docstring text (defaults to 'markdown')." end summary 'Generate documentation from files.' arguments '[[search_pattern] ...]' when_invoked do |*args| check_required_features require 'puppet-strings' PuppetStrings.generate( args.count > 1 ? args[0..-2] : PuppetStrings::DEFAULT_SEARCH_PATTERNS, build_generate_options(args.last) ) nil end end action(:server) do option '--markup FORMAT' do summary "The markup format to use for docstring text (defaults to 'markdown')." end summary 'Runs a local documentation server for the modules in the current Puppet environment.' arguments '[[module_name] ...]' when_invoked do |*args| check_required_features require 'puppet-strings' modules = args.count > 1 ? args[0..-2] : [] # Generate documentation for all (or the given) modules module_docs = [] environment = Puppet.lookup(:current_environment) environment.modules.each do |mod| next unless modules.empty? || modules.include?(mod.name) db = File.join(mod.path, '.yardoc') patterns = PuppetStrings::DEFAULT_SEARCH_PATTERNS.map do |p| File.join(mod.path, p) end puts "Generating documentation for Puppet module '#{mod.name}'." PuppetStrings.generate(patterns, build_generate_options(args.last, '--db', db)) # Clear the registry so that the next call to generate has a clean database YARD::Registry.clear module_docs << mod.name module_docs << db end if module_docs.empty? puts 'No Puppet modules were found to serve documentation for.' return end puts 'Starting YARD documentation server.' PuppetStrings.run_server('-m', *module_docs) nil end end action(:describe) do # This is Kris' experiment with string based describe option '--list' do summary 'list types' end option '--providers' do summary 'provide details on providers for each type' end option '--list-providers' do summary 'list all providers' end # TODO: Implement the rest of describe behavior # * --help: # Print this help text # * --providers: # Describe providers in detail for each type # * --list: # List all types # * --list-providers: # list all providers # * --meta: # List all metaparameters # * --short: # List only parameters without detail when_invoked do |*args| check_required_features require 'puppet-strings' options = args.last options[:describe] = true options[:stdout] = true options[:format] = 'json' if args.length > 1 if options[:list] warn 'WARNING: ignoring types when listing all types.' else options[:describe_types] = args[0..-2] end end # TODO: Set up search_patterns and whatever else needed to collect data for describe - currently missing some # manifests/**/*.pp # functions/**/*.pp # tasks/*.json # plans/*.pp search_patterns = ['types/**/*.pp', 'lib/**/*.rb'] PuppetStrings.generate( search_patterns, build_generate_options(options) ) nil end end # Checks that the required features are installed. # @return [void] def check_required_features raise "The 'yard' gem must be installed in order to use this face." unless Puppet.features.yard? raise "The 'rgen' gem must be installed in order to use this face." unless Puppet.features.rgen? end # Builds the options to PuppetStrings.generate. # @param [Hash] options The Puppet face options hash. # @param [Array] yard_args The additional arguments to pass to YARD. # @return [Hash] Returns the PuppetStrings.generate options hash. def build_generate_options(options = nil, *yard_args) generate_options = {} generate_options[:debug] = Puppet[:debug] generate_options[:backtrace] = Puppet[:trace] generate_options[:yard_args] = yard_args unless yard_args.empty? if options markup = options[:markup] generate_options[:markup] = markup if markup generate_options[:path] = options[:out] if options[:out] generate_options[:stdout] = options[:stdout] if options[:describe] generate_options[:describe] = true generate_options[:describe_types] = options[:describe_types] generate_options[:describe_list] = options[:list] generate_options[:providers] = options[:providers] generate_options[:list_providers] = options[:list_providers] end format = options[:format] if format if format.casecmp('markdown').zero? generate_options[:markdown] = true elsif format.casecmp('json').zero? generate_options[:json] = true else raise "Invalid format #{options[:format]}. Please select 'json' or 'markdown'." end end end generate_options end end puppetlabs-puppet-strings-a4be216/lib/puppet/feature/000077500000000000000000000000001466634474300230405ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/lib/puppet/feature/rgen.rb000066400000000000000000000002171466634474300243200ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet/util/feature' Puppet.features.add(:rgen, libs: ['rgen/metamodel_builder', 'rgen/ecore/ecore']) puppetlabs-puppet-strings-a4be216/lib/puppet/feature/yard.rb000066400000000000000000000001511466634474300243210ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet/util/feature' Puppet.features.add(:yard, libs: ['yard']) puppetlabs-puppet-strings-a4be216/puppet-strings.gemspec000066400000000000000000000014561466634474300237010ustar00rootroot00000000000000# frozen_string_literal: true lib = File.expand_path('lib', __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'puppet-strings/version' Gem::Specification.new do |s| s.name = 'puppet-strings' s.author = 'Puppet Inc.' s.version = PuppetStrings::VERSION s.license = 'Apache-2.0' s.summary = 'Puppet documentation via YARD' s.email = 'info@puppet.com' s.homepage = 'https://github.com/puppetlabs/puppet-strings' s.required_ruby_version = '>= 2.7.0' s.extra_rdoc_files = [ 'CHANGELOG.md', 'CONTRIBUTING.md', 'LICENSE', 'README.md' ] s.files = Dir['CHANGELOG.md', 'README.md', 'LICENSE', 'lib/**/*', 'exe/**/*'] s.add_runtime_dependency 'rgen', '~> 0.9' s.add_runtime_dependency 'yard', '~> 0.9', '< 0.9.37' s.requirements << 'puppet, >= 7.0.0' end puppetlabs-puppet-strings-a4be216/spec/000077500000000000000000000000001466634474300202545ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/acceptance/000077500000000000000000000000001466634474300223425ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/acceptance/generate_json_spec.rb000066400000000000000000000037611466634474300265330ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper_acceptance' describe 'Generating JSON' do let(:test_module_path) do sut_module_path(/Module test/) end let(:remote_tmp_path) do sut_tmp_path end let(:expected) do { 'puppet_classes' => [], 'data_types' => [], 'data_type_aliases' => [], 'defined_types' => [], 'resource_types' => [], 'providers' => [], 'puppet_functions' => [ 'name' => 'function3x', 'file' => "#{test_module_path}/lib/puppet/parser/functions/function3x.rb", 'line' => 3, 'type' => 'ruby3x', 'signatures' => [ { 'signature' => 'function3x()', 'docstring' => { 'text' => 'This is the function documentation for `function3x`', 'tags' => [ { 'tag_name' => 'return', 'text' => '', 'types' => ['Any'] } ] } } ], 'docstring' => { 'text' => 'This is the function documentation for `function3x`', 'tags' => ['tag_name' => 'return', 'text' => '', 'types' => ['Any']] }, 'source' => "Puppet::Parser::Functions.newfunction(:function3x, :doc => \"This is the function documentation for `function3x`\") do |args|\nend" ], 'puppet_tasks' => [], 'puppet_plans' => [] } end it 'renders JSON to stdout when using --format json' do output = run_shell("puppet strings generate --format json \"#{test_module_path}/lib/puppet/parser/functions/function3x.rb\"").stdout.chomp expect(JSON.parse(output)).to eq(expected) end it 'writes JSON to a file when using --format json --out' do tmpfile = File.join(remote_tmp_path, 'json_output.json') run_shell("puppet strings generate --format json --out #{tmpfile} \"#{test_module_path}/lib/puppet/parser/functions/function3x.rb\"") expect(JSON.parse(file(tmpfile).content)).to eq(expected) end end puppetlabs-puppet-strings-a4be216/spec/acceptance/generate_markdown_spec.rb000066400000000000000000000023721466634474300274010ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper_acceptance' describe 'Generating Markdown' do let(:test_module_path) do sut_module_path(/Module test/) end let(:remote_tmp_path) do sut_tmp_path end expected = <<~EOF # Reference ## Classes * [`test`](#test): This class exists to serve as fixture data for testing the puppet strings face ## Classes ### test #### Examples ```puppet class { "test": } ``` #### Parameters ##### `package_name` The name of the package ##### `service_name` The name of the service EOF it 'renders Markdown to stdout when using --format markdown' do skip('This test is broken. Does not output to STDOUT by default.') output = PuppetLitmus::PuppetHelpers.run_shell("puppet strings generate --format markdown \"#{test_module_path}/manifests/init.pp\"").stdout.chomp expect(output).to eq(expected) end it 'writes Markdown to a file when using --format markdown and --out' do tmpfile = File.join(remote_tmp_path, 'md_output.md') PuppetLitmus::PuppetHelpers.run_shell("puppet strings generate --format markdown --out \"#{tmpfile}\" \"#{test_module_path}/manifests/init.pp\"") expect(file(tmpfile)).to contain expected end end puppetlabs-puppet-strings-a4be216/spec/acceptance/running_strings_generate_spec.rb000066400000000000000000000077141466634474300310150ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper_acceptance' include PuppetLitmus describe 'Generating module documentation using generate action' do let(:sut_work_dir) do PuppetLitmus::PuppetHelpers.run_shell('pwd').stdout.chomp end before :all do # TODO: Linux only test_module_path = sut_module_path(/Module test/) PuppetLitmus::PuppetHelpers.run_shell("puppet strings generate \"#{test_module_path}/**/*.{rb,pp}\"") end def expect_file_contain(path, expected_contents) file_path = File.join(sut_work_dir, path) file_content = file(file_path).content expected_contents.each do |expected| expect(file_content).to include(expected) end end it 'generates documentation for manifests' do expect_file_contain('doc/puppet_classes/test.html', ['Class: test']) end it 'generates documentation for puppet functions' do skip('This test is failing. Appear to be legitimate failures.') expect_file_contain('doc/puppet_functions_puppet/test_3A_3Aadd.html', [ 'Adds two integers together.', # These tests are failing. Appear to be legitimate failures. '

    The first integer to add.

    ', '

    The second integer to add.

    ', '

    Returns the sum of x and y.

    ' ]) end it 'generates documentation for 3x functions' do expect_file_contain('doc/puppet_functions_ruby3x/function3x.html', ['This is the function documentation for function3x']) end it 'generates documentation for 4x functions' do expect_file_contain('doc/puppet_functions_ruby4x/function4x.html', ['This is a function which is used to test puppet strings']) end it 'generates documentation for custom types' do expect_file_contain('doc/puppet_types/database.html', [ '

    An example server resource type.

    ', '

    The database file to use.

    ', '

    Documentation for a dynamic property.

    ', '

    The database server name.

    ', '

    Documentation for a dynamic parameter.

    ', '

    The provider supports encryption.

    ' ]) end it 'generates documentation for custom providers' do expect_file_contain('doc/puppet_providers_database/linux.html', [ 'The database provider on Linux', 'osfamily — linux', 'database — /usr/bin/database' ]) end it 'generates documentation for puppet data types' do expect_file_contain('doc/puppet_data_types/AcceptanceDataType.html', [ 'A variant parameter called param1', 'Optional String parameter called param2', '

    func1

    ', '

    func1 documentation

    ', '

    param1 func1 documentation

    ', '

    param2 func1 documentation

    ' ]) end it 'generates documentation for puppet data type aliases' do expect_file_contain('doc/puppet_data_type_aliases/Test_3A_3AElephant.html', [ 'Data Type: Test::Elephant', 'types/elephant.pp', 'A simple elephant type.' ]) end it 'generates documentation for enum tag' do expect_file_contain('doc/puppet_classes/test.html', [ '

    Enum Options (myenum):

    ', 'a', "—

    Option A

    \n
    ", 'b', "—

    Option B

    \n
    " ]) end end puppetlabs-puppet-strings-a4be216/spec/fixtures/000077500000000000000000000000001466634474300221255ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/000077500000000000000000000000001466634474300242135ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/000077500000000000000000000000001466634474300256635ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/000077500000000000000000000000001466634474300266425ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/functions/000077500000000000000000000000001466634474300306525ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/functions/add.pp000066400000000000000000000004261466634474300317450ustar00rootroot00000000000000# Adds two integers together. # @param x The first integer to add. # @param y The second integer to add. # @return [Integer] Returns the sum of x and y. # @example Example of adding two integers. # test::add(1, 2) => 3 function test::add(Integer $x, Integer $y) { $x + $y } puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/000077500000000000000000000000001466634474300274105ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/puppet/000077500000000000000000000000001466634474300307255ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/puppet/datatypes/000077500000000000000000000000001466634474300327235ustar00rootroot00000000000000acceptancedatatype.rb000066400000000000000000000013021466634474300370070ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/puppet/datatypes# frozen_string_literal: true # An example Acceptance Puppet Data Type in Ruby. # # @param param1 A variant parameter called param1. # @param param2 Optional String parameter called param2. # @method func1(param1, param2) # func1 documentation # @param [String] param1 param1 func1 documentation # @param [Integer] param2 param2 func1 documentation # @return [Optional[String]] Puppet::DataTypes.create_type('AcceptanceDataType') do interface <<~'PUPPET' attributes => { param1 => Variant[Numeric, String[1,2]], param2 => { type => Optional[String[1]], value => "param2" } }, functions => { func1 => Callable[[String, Integer], Optional[String]] } PUPPET end puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/puppet/functions/000077500000000000000000000000001466634474300327355ustar00rootroot000000000000004x_function.rb000066400000000000000000000002371466634474300354450ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/puppet/functions# frozen_string_literal: true # function 4x # # This is a function which is used to test puppet strings Puppet::Functions.create_function(:function4x) do end puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/puppet/parser/000077500000000000000000000000001466634474300322215ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/puppet/parser/functions/000077500000000000000000000000001466634474300342315ustar00rootroot00000000000000function3x.rb000066400000000000000000000002371466634474300366010ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/puppet/parser/functions# frozen_string_literal: true Puppet::Parser::Functions.newfunction(:function3x, :doc => "This is the function documentation for `function3x`") do |args| end puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/puppet/provider/000077500000000000000000000000001466634474300325575ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/puppet/provider/server/000077500000000000000000000000001466634474300340655ustar00rootroot00000000000000linux.rb000066400000000000000000000003641466634474300354750ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/puppet/provider/server# frozen_string_literal: true Puppet::Type.type(:database).provide :linux do confine 'osfamily' => 'linux' defaultfor 'osfamily' => 'linux' commands :database => '/usr/bin/database' desc 'The database provider on Linux.' # ... end puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/puppet/type/000077500000000000000000000000001466634474300317065ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/lib/puppet/type/database.rb000066400000000000000000000010141466634474300337730ustar00rootroot00000000000000# frozen_string_literal: true # @!puppet.type.param [value1, value2, value3] my_param Documentation for a dynamic parameter. # @!puppet.type.property [foo, bar, baz] my_prop Documentation for a dynamic property. Puppet::Type.newtype(:database) do desc 'An example server resource type.' feature :encryption, 'The provider supports encryption.', methods: [:encrypt] newparam(:address) do isnamevar desc 'The database server name.' end newproperty(:file) do desc 'The database file to use.' end end puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/manifests/000077500000000000000000000000001466634474300306335ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/manifests/init.pp000066400000000000000000000012371466634474300321420ustar00rootroot00000000000000# Class: test # # This class exists to serve as fixture data for testing the puppet strings face # # @example # class { "test": } # # @param package_name The name of the package # @param service_name The name of the service # @param myenum # @enum myenum a Option A # @enum myenum b Option B class test ( $package_name = $test::params::package_name, $service_name = $test::params::service_name, Enum['a', 'b'] $myenum = 'a', ) inherits test::params { # validate parameters here class { 'test::install': } -> class { 'test::config': } ~> class { 'test::service': } -> Class['test'] File { owner => 'user', path => 'some/file/path', } } triple_nested_classes.pp000066400000000000000000000012411466634474300354710ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/manifests# Testing tested classes # docs stuff # @param nameservers [String] Don't ask me what this does! # @param default_lease_time [Integer[1024, 8192]] text goes here # @param max_lease_time does stuff class outer ( $dnsdomain, $nameservers, $default_lease_time = 3600, $max_lease_time = 86400 ) { # @param options [String[5,7]] gives user choices # @param multicast [Boolean] foobar # @param servers yep, that's right class middle ( $options = "iburst", $servers, $multicast = false ) { class inner ( $choices = "uburst", $secenekler = "weallburst", $boxen, $manyspell = true ) {} } } puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/metadata.json000066400000000000000000000003131466634474300313120ustar00rootroot00000000000000{ "name": "username-test", "version": "0.0.1", "author": "username", "summary": "brief summary", "license": "MIT", "source": "git://github.com/not_a/real_repo.git", "dependencies": [ ] } puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/types/000077500000000000000000000000001466634474300300065ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/acceptance/modules/test/types/elephant.pp000066400000000000000000000000721466634474300321460ustar00rootroot00000000000000# A simple elephant type. type Test::Elephant = String[2] puppetlabs-puppet-strings-a4be216/spec/fixtures/json/000077500000000000000000000000001466634474300230765ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/json/backup.json000066400000000000000000000010111466634474300252270ustar00rootroot00000000000000{ "description": "Allows you to backup your database to local file.", "input_method": "stdin", "parameters": { "database": { "description": "Database to connect to", "type": "Optional[String[1]]" }, "user": { "description": "The user", "type": "Optional[String[1]]" }, "password": { "description": "The password", "type": "Optional[String[1]]" }, "sql": { "description": "Path to file you want backup to", "type": "String[1]" } } } puppetlabs-puppet-strings-a4be216/spec/fixtures/plans/000077500000000000000000000000001466634474300232425ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/plans/plan.pp000066400000000000000000000002461466634474300245370ustar00rootroot00000000000000# A simple plan. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. plan plann(String $param1, $param2, Integer $param3 = 1) { } puppetlabs-puppet-strings-a4be216/spec/fixtures/puppet/000077500000000000000000000000001466634474300234425ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/puppet/class.pp000066400000000000000000000031431466634474300251110ustar00rootroot00000000000000# An overview for a simple class. # @summary A simple class. # @todo Do a thing # @deprecated No longer supported and will be removed in a future release # @note some note # @since 1.0.0 # @see www.puppet.com # @example This is an example # class { 'klass': # param1 => 1, # param3 => 'foo', # } # @example This is another example # class { 'klass': # param1 => 1, # param3 => 'foo', # } # @raise SomeError # @param param1 First param. # @param param2 Second param. # @option param2 [String] :opt1 something about opt1 # @option param2 [Hash] :opt2 a hash of stuff # @param param3 Third param. # @param param4 Fourth param. # @enum param4 :one One option # @enum param4 :two Second option # class klass ( Integer $param1 = 1, $param2 = undef, String $param3 = 'hi', Enum['one', 'two'] $param4 = 'two', ) inherits foo::bar { } # Overview for class noparams # @api private class noparams () {} # An overview for a simple defined type. # @summary A simple defined type. # @since 1.1.0 # @see www.puppet.com # @example Here's an example of this type: # klass::dt { 'foo': # param1 => 33, # param4 => false, # } # @return shouldn't return squat # @raise SomeError # @param param1 First param. # @param param2 Second param. # @option param2 [String] :opt1 something about opt1 # @option param2 [Hash] :opt2 a hash of stuff # @param param3 Third param. # @param param4 Fourth param. # @param param5 Fifth param. # @enum param5 :a Option A # @enum param5 :b Option B define klass::dt ( Integer $param1 = 44, $param2, String $param3 = 'hi', Boolean $param4 = true, Enum['a', 'b'] $param5 = 'a' ) { } puppetlabs-puppet-strings-a4be216/spec/fixtures/puppet/function.pp000066400000000000000000000007461466634474300256370ustar00rootroot00000000000000# A simple Puppet function. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. # @option param3 [Array] :param3opt Something about this option # @param param4 Fourth param. # @enum param4 :yes Yes option. # @enum param4 :no No option. # @raise SomeError this is some error # @return [Undef] Returns nothing. # @example Test # $result = func(1, 2) function func(Integer $param1, $param2, String $param3 = hi, Enum['yes', 'no'] $param4 = 'yes') { } puppetlabs-puppet-strings-a4be216/spec/fixtures/puppet/type_alias.pp000066400000000000000000000004001466634474300261270ustar00rootroot00000000000000# Documentation for Amodule::SimpleAlias type Amodule::SimpleAlias = Variant[Numeric,String[1,20]] # Documentation for Amodule::ComplexAlias type Amodule::ComplexAlias = Struct[{ value_type => Optional[ValueType], merge => Optional[MergeType] }] puppetlabs-puppet-strings-a4be216/spec/fixtures/ruby/000077500000000000000000000000001466634474300231065ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/fixtures/ruby/data_type.rb000066400000000000000000000011531466634474300254050ustar00rootroot00000000000000# An example Puppet Data Type in Ruby. # # @param param1 A variant parameter. # @param param2 Optional String parameter. # @!method func1(param1, param2) # func1 documentation # @param [String] param1 param1 documentation # @param [Integer] param2 param2 documentation # @return [Optional[String]] Puppet::DataTypes.create_type('UnitDataType') do interface <<~'PUPPET' attributes => { param1 => Variant[Numeric, String[1,2]], param2 => { type => Optional[String[1]], value => "param2" } }, functions => { func1 => Callable[[String, Integer], Optional[String]] } PUPPET end puppetlabs-puppet-strings-a4be216/spec/fixtures/ruby/func3x.rb000066400000000000000000000005161466634474300246430ustar00rootroot00000000000000# An example 3.x function Puppet::Parser::Functions.newfunction(:func3x, doc: <<~'DOC') do |*args| Documentation for an example 3.x function. @param param1 [String] The first parameter. @param param2 [Integer] The second parameter. @return [Undef] @example Calling the function. func3x('hi', 10) DOC # ... end puppetlabs-puppet-strings-a4be216/spec/fixtures/ruby/func4x.rb000066400000000000000000000024121466634474300246410ustar00rootroot00000000000000# An example 4.x function. # # @example Calling the function # $result = func4x(1, 'foo') # # @example Calling the function with all args # $result = func4x(1, 'foo', ['bar']) Puppet::Functions.create_function(:func4x) do # An overview for the first overload. # @raise SomeError this is some error # @param param1 The first parameter. # @param param2 The second parameter. # @option param2 [String] :option an option # @option param2 [String] :option2 another option # @param param3 The third parameter. # @param param4 The fourth parameter. # @enum param4 :one Option one. # @enum param4 :two Option two. # @return Returns nothing. # @example Calling the function foo # $result = func4x(1, 'foooo') # dispatch :foo do param 'Integer', :param1 param 'Any', :param2 optional_param 'Array[String]', :param3 optional_param 'Enum[one, two]', :param4 return_type 'Undef' end # An overview for the second overload. # @param param The first parameter. # @param block The block parameter. # @return Returns a string. # @example Calling the function bar # $result = func4x(1, 'bar', ['foo']) dispatch :other do param 'Boolean', :param block_param return_type 'String' end end puppetlabs-puppet-strings-a4be216/spec/fixtures/ruby/func4x_1.rb000066400000000000000000000003771466634474300250710ustar00rootroot00000000000000# An example 4.x function with only one signature. Puppet::Functions.create_function(:func4x_1) do # @param param1 The first parameter. # @return [Undef] Returns nothing. dispatch :foobarbaz do param 'Integer', :param1 end end puppetlabs-puppet-strings-a4be216/spec/fixtures/ruby/provider.rb000066400000000000000000000005401466634474300252640ustar00rootroot00000000000000Puppet::Type.type(:database).provide :linux do desc 'An example provider on Linux.' confine kernel: 'Linux' confine osfamily: 'RedHat' defaultfor :kernel => 'Linux' defaultfor :osfamily => 'RedHat', :operatingsystemmajrelease => '7' has_feature :implements_some_feature has_feature :some_other_feature commands foo: '/usr/bin/foo' end puppetlabs-puppet-strings-a4be216/spec/fixtures/ruby/resource_api.rb000066400000000000000000000025231466634474300261150ustar00rootroot00000000000000Puppet::ResourceApi.register_type( name: 'apt_key', docs: <<~'EOS', @summary Example resource type using the new API. @raise SomeError This type provides Puppet with the capabilities to manage GPG keys needed by apt to perform package validation. Apt has it's own GPG keyring that can be manipulated through the `apt-key` command. @example here's an example apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F': source => 'http://apt.puppetlabs.com/pubkey.gpg' } **Autorequires**: If Puppet is given the location of a key file which looks like an absolute path this type will autorequire that file. EOS attributes: { ensure: { type: 'Enum[present, absent]', desc: 'Whether this apt key should be present or absent on the target system.' }, id: { type: 'Variant[Pattern[/\A(0x)?[0-9a-fA-F]{8}\Z/], Pattern[/\A(0x)?[0-9a-fA-F]{16}\Z/], Pattern[/\A(0x)?[0-9a-fA-F]{40}\Z/]]', behaviour: :namevar, desc: 'The ID of the key you want to manage.', }, # ... created: { type: 'String', behaviour: :read_only, desc: 'Date the key was created, in ISO format.', }, }, autorequires: { file: '$source', # will evaluate to the value of the `source` attribute package: 'apt', }, ) puppetlabs-puppet-strings-a4be216/spec/fixtures/ruby/resource_type.rb000066400000000000000000000022421466634474300263230ustar00rootroot00000000000000Puppet::Type.newtype(:database) do desc <<~'DESC' An example database server type. @option opts :foo bar @enum ensure :up Upstate @enum ensure :down Downstate @raise SomeError @example here's an example database { 'foo': address => 'qux.baz.bar', } DESC feature :encryption, 'The provider supports encryption.', methods: [:encrypt] ensurable do desc 'What state the database should be in.' defaultvalues aliasvalue(:up, :present) aliasvalue(:down, :absent) defaultto :up end newparam(:address) do isnamevar desc 'The database server name.' end newparam(:encryption_key, required_features: :encryption) do desc 'The encryption key to use.' end newparam(:encrypt, :parent => Puppet::Parameter::Boolean) do desc 'Whether or not to encrypt the database.' defaultto false end newproperty(:file) do desc 'The database file to use.' end newproperty(:log_level) do desc 'The log level to use.' newvalue(:debug) newvalue(:warn) newvalue(:error) defaultto 'warn' end newcheck(:exists) do desc 'Check to see if the database already exists' end end puppetlabs-puppet-strings-a4be216/spec/markdownlint_style.rb000066400000000000000000000004001466634474300245240ustar00rootroot00000000000000# frozen_string_literal: true all # Update line length to 120 chars. rule 'MD013', line_length: 120 # Allow duplicate headings. exclude_rule 'MD024' # Allow trailing punctuation in headings. exclude_rule 'MD026' # Allow html tags exclude_rule 'MD033' puppetlabs-puppet-strings-a4be216/spec/spec_helper.rb000066400000000000000000000047151466634474300231010ustar00rootroot00000000000000# frozen_string_literal: true if ENV['COVERAGE'] == 'yes' require 'simplecov' require 'simplecov-console' SimpleCov.formatters = [ SimpleCov::Formatter::HTMLFormatter, SimpleCov::Formatter::Console ] SimpleCov.start do track_files 'lib/**/*.rb' add_filter 'lib/puppet-strings/version.rb' add_filter '/spec' end end require 'mocha' require 'mdl' require 'rspec' require 'json_spec' require 'puppet/version' require 'puppet-strings' require 'puppet-strings/markdown' require 'puppet-strings/markdown/base' require 'puppet-strings/yard' # Explicitly set up YARD once PuppetStrings::Yard.setup! # Enable testing of Puppet functions if running against 4.1+ TEST_PUPPET_FUNCTIONS = Puppet::Util::Package.versioncmp(Puppet.version, '4.1.0') >= 0 # Enable testing of Puppet language functions declared with return type if running against 4.8+ TEST_FUNCTION_RETURN_TYPE = Puppet::Util::Package.versioncmp(Puppet.version, '4.8.0') >= 0 # Enable testing of Plans if Puppet version is greater than 5.0.0 TEST_PUPPET_PLANS = Puppet::Util::Package.versioncmp(Puppet.version, '5.0.0') >= 0 # Enable testing of Data Types if Puppet version is greater than 4.1.0 TEST_PUPPET_DATATYPES = Puppet::Util::Package.versioncmp(Puppet.version, '4.1.0') >= 0 RSpec.configure do |config| config.mock_with :mocha config.before do # Always clear the YARD registry before each example YARD::Registry.clear end end def lint_markdown(content) # Load default mdl ruleset ruleset = MarkdownLint::RuleSet.new.tap(&:load_default) # Apply custom style to ruleset rules MarkdownLint::Style.load(File.join(__dir__, 'markdownlint_style.rb'), ruleset.rules) # Create a document doc = MarkdownLint::Doc.new(content, false) # Run the rules violations = [] ruleset.rules.each do |id, rule| error_lines = rule.check.call(doc) next if error_lines.nil? || error_lines.empty? # record the error error_lines.each do |line| line += doc.offset # Correct line numbers for any yaml front matter violations << "#{line}: #{id} #{rule.description}: #{doc.lines[line - 1]}" end end violations end RSpec::Matchers.define :have_no_markdown_lint_errors do match do |actual| @violations = lint_markdown(actual) @violations.empty? end failure_message do |actual| "expected that #{actual.length > 80 ? "#{actual.slice(0, 80).inspect}..." : actual.inspect} would have no markdown lint errors but got #{@violations.join("\n")}" end end puppetlabs-puppet-strings-a4be216/spec/spec_helper_acceptance.rb000066400000000000000000000003131466634474300252350ustar00rootroot00000000000000# frozen_string_literal: true require 'puppet_litmus' require 'spec_helper_acceptance_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_acceptance_local.rb')) PuppetLitmus.configure! puppetlabs-puppet-strings-a4be216/spec/spec_helper_acceptance_local.rb000066400000000000000000000006201466634474300264100ustar00rootroot00000000000000# frozen_string_literal: true def sut_module_path(module_regex) modules = JSON.parse(run_shell('bundle exec puppet module list --modulepath spec/fixtures/modules --render-as json').stdout) test_module_info = modules['modules_by_path'].values.flatten.find { |mod_info| mod_info =~ module_regex } test_module_info.match(/\(([^)]*)\)/)[1] end def sut_tmp_path # TODO: Linux only '/tmp/' end puppetlabs-puppet-strings-a4be216/spec/unit/000077500000000000000000000000001466634474300212335ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/000077500000000000000000000000001466634474300242375ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/describe_spec.rb000066400000000000000000000110141466634474300273530ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/describe' require 'tempfile' # TODO: basic describe # params from other files (e.g. file content) #--providers - list providers in detail # X--list - list all providers summary #--meta - List all metaparameters #--short - only list params describe PuppetStrings::Describe do before do # Populate the YARD registry with both Puppet and Ruby source YARD::Parser::SourceParser.parse_string(<<~SOURCE, :ruby) Puppet::Type.newtype(:database) do desc 'An example database server resource type.' end SOURCE YARD::Parser::SourceParser.parse_string(<<~SOURCE, :ruby) Puppet::ResourceApi.register_type( name: 'apt_key', docs: <<~'EOS', @summary Example resource type using the new API. @raise SomeError This type provides Puppet with the capabilities to manage GPG keys needed by apt to perform package validation. Apt has it's own GPG keyring that can be manipulated through the `apt-key` command. @example here's an example apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F': source => 'http://apt.puppetlabs.com/pubkey.gpg' } **Autorequires**: If Puppet is given the location of a key file which looks like an absolute path this type will autorequire that file. EOS ) SOURCE YARD::Parser::SourceParser.parse_string(<<~SOURCE, :ruby) Puppet::Type.type(:file).newproperty(:content) do include Puppet::Util::Checksums include Puppet::DataSync attr_reader :actual_content desc <<~'EOT' The desired contents of a file, as a string. This attribute is mutually exclusive with `source` and `target`. EOT end SOURCE YARD::Parser::SourceParser.parse_string(<<~'SOURCE', :ruby) Puppet::Type.newtype(:file) do include Puppet::Util::Checksums include Puppet::Util::Backups include Puppet::Util::SymbolicFileMode @doc = "Manages files, including their content, ownership, and permissions. The `file` type can manage normal files, directories, and symlinks; the type should be specified in the `ensure` attribute." newparam(:path) do desc <<~'EOT' The path to the file to manage. Must be fully qualified. On Windows, the path should include the drive letter and should use `/` as the separator character (rather than `\`). EOT isnamevar end end SOURCE YARD::Parser::SourceParser.parse_string(<<~SOURCE, :ruby) Puppet::Type.type(:file).newproperty(:source) do include Puppet::Util::Checksums include Puppet::DataSync attr_reader :actual_content desc <<-'EOT' The desired contents of a file, as a string. This attribute is mutually exclusive with `source` and `target`. EOT end SOURCE end describe 'rendering DESCRIBE to stdout' do it 'outputs the expected describe content for the list of types' do output = <<~DATA These are the types known to puppet: apt_key - This type provides Puppet with the capabiliti ... database - An example database server resource type. file - Manages files, including their content, owner ... DATA expect { described_class.render(nil, true) }.to output(output).to_stdout end it 'outputs the expected describe content for a type' do output = <<~'DATA' file ==== Manages files, including their content, ownership, and permissions. The `file` type can manage normal files, directories, and symlinks; the type should be specified in the `ensure` attribute. Parameters ---------- - **content** The desired contents of a file, as a string. This attribute is mutually exclusive with `source` and `target`. - **path** The path to the file to manage. Must be fully qualified. On Windows, the path should include the drive letter and should use `/` as the separator character (rather than `\`). - **source** The desired contents of a file, as a string. This attribute is mutually exclusive with `source` and `target`. Providers --------- DATA expect { described_class.render(['file']) }.to output(output).to_stdout end end end puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/json_spec.rb000066400000000000000000000251371466634474300265570ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/json' require 'tempfile' describe PuppetStrings::Json do before do # Populate the YARD registry with both Puppet and Ruby source expect(YARD::Parser::SourceParser.parse_string(<<~SOURCE, :puppet).enumerator.length).to eq(2) # A simple class. # @todo Do a thing # @deprecated No longer supported and will be removed in a future release # @note Some note # @param param1 First param. # @param param2 Second param. # @param param3 Third param. class klass(Integer $param1, $param2, String $param3 = hi) inherits foo::bar { } # A simple defined type. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. define dt(Integer $param1, $param2, String $param3 = hi) { } SOURCE expect(YARD::Parser::SourceParser.parse_string(<<~SOURCE, :puppet).enumerator.length).to eq(1) if TEST_PUPPET_PLANS # A simple plan. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. plan plann(String $param1, $param2, Integer $param3 = 1) { } SOURCE # Only include Puppet functions for 4.1+ expect(YARD::Parser::SourceParser.parse_string(<<~SOURCE, :puppet).enumerator.length).to eq(1) if TEST_PUPPET_FUNCTIONS # A simple function. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. # @return [Undef] Returns nothing. function func(Integer $param1, $param2, String $param3 = hi) { } SOURCE # Only include Puppet types for 5.0+ expect(YARD::Parser::SourceParser.parse_string(<<~SOURCE, :ruby).enumerator.length).to eq(1) if TEST_PUPPET_DATATYPES # Basic Puppet Data Type in Ruby # # @param msg A message parameter # @!method func1(param1, param2) # func1 documentation # @param [String] param1 param1 documentation # @param [Integer] param2 param2 documentation # @return [Optional[String]] Puppet::DataTypes.create_type('RubyDataType') do interface <<~'PUPPET' attributes => { msg => String[1] }, functions => { func1 => Callable[[String, Integer], Optional[String]] } PUPPET end SOURCE expect(YARD::Parser::SourceParser.parse_string(<<~SOURCE, :json).enumerator.length).to eq(1) { "description": "Allows you to backup your database to local file.", "input_method": "stdin", "parameters": { "database": { "description": "Database to connect to", "type": "Optional[String[1]]" }, "user": { "description": "The user", "type": "Optional[String[1]]" }, "password": { "description": "The password", "type": "Optional[String[1]]" }, "sql": { "description": "Path to file you want backup to", "type": "String[1]" } } } SOURCE expect(YARD::Parser::SourceParser.parse_string(<<~'SOURCE', :ruby).enumerator.length).to eq(6) Puppet::Parser::Functions.newfunction(:func3x, doc: <<~'DOC') do |*args| An example 3.x function. @param [String] first The first parameter. @param second The second parameter. @return [Undef] Returns nothing. DOC end # An example 4.x function. Puppet::Functions.create_function(:func4x) do # The first overload. # @param param1 The first parameter. # @param param2 The second parameter. # @param param3 The third parameter. # @return Returns nothing. dispatch :foo do param 'Integer', :param1 param 'Any', :param2 optional_param 'Array[String]', :param3 return_type 'Undef' end # @param param The first parameter. # @param block The block parameter. # @return Returns a string. dispatch :other do param 'Boolean', :param block_param return_type 'String' end end # An example 4.x function with only one signature. Puppet::Functions.create_function(:func4x_1) do # @param param1 The first parameter. # @return [Undef] Returns nothing. dispatch :foobarbaz do param 'Integer', :param1 end end Puppet::Type.type(:database).provide :linux do desc 'An example provider on Linux.' confine kernel: 'Linux' confine osfamily: 'RedHat' defaultfor :kernel => 'Linux' defaultfor :osfamily => 'RedHat', :operatingsystemmajrelease => '7' has_feature :implements_some_feature has_feature :some_other_feature commands foo: '/usr/bin/foo' end Puppet::Type.newtype(:database) do desc 'An example database server resource type.' feature :encryption, 'The provider supports encryption.', methods: [:encrypt] ensurable do desc 'What state the database should be in.' defaultvalues aliasvalue(:up, :present) aliasvalue(:down, :absent) defaultto :up end newparam(:address) do isnamevar desc 'The database server name.' end newparam(:encryption_key, required_features: :encryption) do desc 'The encryption key to use.' end newparam(:encrypt, :parent => Puppet::Parameter::Boolean) do desc 'Whether or not to encrypt the database.' defaultto false end newproperty(:file) do desc 'The database file to use.' end newproperty(:log_level) do desc 'The log level to use.' newvalue(:debug) newvalue(:warn) newvalue(:error) defaultto 'warn' end end Puppet::ResourceApi.register_type( name: 'apt_key', docs: <<~'EOS', @summary Example resource type using the new API. @raise SomeError This type provides Puppet with the capabilities to manage GPG keys needed by apt to perform package validation. Apt has it's own GPG keyring that can be manipulated through the `apt-key` command. @example here's an example apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F': source => 'http://apt.puppetlabs.com/pubkey.gpg' } **Autorequires**: If Puppet is given the location of a key file which looks like an absolute path this type will autorequire that file. EOS attributes: { ensure: { type: 'Enum[present, absent]', desc: 'Whether this apt key should be present or absent on the target system.' }, id: { type: 'Variant[Pattern[/\A(0x)?[0-9a-fA-F]{8}\Z/], Pattern[/\A(0x)?[0-9a-fA-F]{16}\Z/], Pattern[/\A(0x)?[0-9a-fA-F]{40}\Z/]]', behaviour: :namevar, desc: 'The ID of the key you want to manage.', }, # ... created: { type: 'String', behaviour: :read_only, desc: 'Date the key was created, in ISO format.', }, }, autorequires: { file: '$source', # will evaluate to the value of the `source` attribute package: 'apt', }, ) SOURCE end RSpec.shared_examples 'correct JSON' do it 'includes data for Puppet Classes' do expected = YARD::Registry.all(:puppet_class).sort_by!(&:name).map!(&:to_hash).to_json actual = capture_output { described_class.render(nil) } expect(actual[:stdout]).to include_json(expected) end it 'includes data for Puppet Data Types' do expected = YARD::Registry.all(:puppet_data_type).sort_by!(&:name).map!(&:to_hash).to_json actual = capture_output { described_class.render(nil) } expect(actual[:stdout]).to include_json(expected) end it 'includes data for Puppet Defined Types' do expected = YARD::Registry.all(:puppet_defined_type).sort_by!(&:name).map!(&:to_hash).to_json actual = capture_output { described_class.render(nil) } expect(actual[:stdout]).to include_json(expected) end it 'includes data for Puppet Resource Types' do expected = YARD::Registry.all(:puppet_type).sort_by!(&:name).map!(&:to_hash).to_json actual = capture_output { described_class.render(nil) } expect(actual[:stdout]).to include_json(expected) end it 'includes data for Puppet Providers' do expected = YARD::Registry.all(:puppet_provider).sort_by!(&:name).map!(&:to_hash).to_json actual = capture_output { described_class.render(nil) } expect(actual[:stdout]).to include_json(expected) end it 'includes data for Puppet Functions', if: TEST_PUPPET_FUNCTIONS do expected = YARD::Registry.all(:puppet_function).sort_by!(&:name).map!(&:to_hash).to_json actual = capture_output { described_class.render(nil) } expect(actual[:stdout]).to include_json(expected) end it 'includes data for Puppet Tasks' do expected = YARD::Registry.all(:puppet_task).sort_by!(&:name).map!(&:to_hash).to_json actual = capture_output { described_class.render(nil) } expect(actual[:stdout]).to include_json(expected) end it 'includes data for Puppet Plans', if: TEST_PUPPET_PLANS do expected = YARD::Registry.all(:puppet_plan).sort_by!(&:name).map!(&:to_hash).to_json actual = capture_output { described_class.render(nil) } expect(actual[:stdout]).to include_json(expected) end end describe 'rendering JSON to a file' do let(:json_output) do json_output = nil Tempfile.open('json') do |file| described_class.render(file.path) json_output = File.read(file.path) end json_output end include_examples 'correct JSON' end describe 'rendering JSON to stdout' do include_examples 'correct JSON' end end # Helper method to capture stdout and stderr from a block # Source: https://gist.github.com/herrphon/2d2ebbf23c86a10aa955 # # @param [Proc] block The block to capture output from # @return [Hash] A hash containing the captured output def capture_output(&_block) begin $stdout = StringIO.new $stderr = StringIO.new yield result = {} result[:stdout] = $stdout.string result[:stderr] = $stderr.string ensure $stdout = STDOUT $stderr = STDERR end result end puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/markdown/000077500000000000000000000000001466634474300260615ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/markdown/base_spec.rb000066400000000000000000000075011466634474300303350ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' describe PuppetStrings::Markdown::Base do context 'basic class' do before do YARD::Parser::SourceParser.parse_string(<<~SOURCE, :puppet) # An overview # @api private # @summary A simple class. # @deprecated No longer supported and will be removed in a future release # @param param1 First param. # @param param2 Second param. # @param param3 Third param. class klass(Integer $param1, $param2, String $param3 = hi) inherits foo::bar { } SOURCE end let(:reg) { YARD::Registry.all(:puppet_class).sort_by!(&:name).map!(&:to_hash)[0] } let(:component) { described_class.new(reg, 'class') } describe '#name' do it 'returns the expected name' do expect(component.name).to eq 'klass' end end %w[examples see since return_val return_type].each do |method| describe "##{method}" do it 'returns nil' do expect(component.method(method.to_sym).call).to be_nil end end end describe '#private?' do it do expect(component.private?).to be true end end describe '#params' do it 'returns the expected params' do expect(component.params.size).to eq 3 end end describe '#summary' do it 'returns the expected summary' do expect(component.summary).to eq 'A simple class.' end end describe '#deprecated' do it 'returns the expected deprecated warning' do expect(component.deprecated).to eq 'No longer supported and will be removed in a future release' end end describe '#toc_info' do let(:toc) { component.toc_info } it 'returns a hash' do expect(toc).to be_instance_of Hash end it 'prefers the summary for :desc' do expect(toc[:desc]).to eq 'A simple class.' end end end context 'less basic class' do before do YARD::Parser::SourceParser.parse_string(<<~SOURCE, :puppet) # An overview # It's a longer overview # Ya know? # @example A simple example. # class { 'klass::yeah': # param1 => 1, # } # @param param1 First param. # @param param2 Second param. # @param param3 Third param. class klass::yeah( Integer $param1, $param2, String $param3 = hi ) inherits foo::bar { } SOURCE end let(:reg) { YARD::Registry.all(:puppet_class).sort_by!(&:name).map!(&:to_hash)[0] } let(:component) { described_class.new(reg, 'class') } describe '#name' do it 'returns the expected name' do expect(component.name).to eq 'klass::yeah' end end %w[summary see since return_val return_type].each do |method| describe "##{method}" do it 'returns nil' do expect(component.method(method.to_sym).call).to be_nil end end end describe '#examples' do it 'returns one example' do expect(component.examples.size).to eq 1 end end describe '#params' do it 'returns the expected params' do expect(component.params.size).to eq 3 end end describe '#private?' do it do expect(component.private?).to be false end end describe '#toc_info' do let(:toc) { component.toc_info } it 'returns a hash' do expect(toc).to be_instance_of Hash end it 'uses overview for :desc in absence of summary' do expect(toc[:desc]).to eq 'An overview It\'s a longer overview Ya know?' end end describe '#link' do it 'returns a valid link' do expect(component.link).to eq 'klass--yeah' end end end end puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/markdown_spec.rb000066400000000000000000000236541466634474300274320ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/markdown' require 'tempfile' describe PuppetStrings::Markdown do describe 'rendering fixtures' do let(:fixture_path) do File.expand_path('../../fixtures', __dir__) end let(:output) { described_class.generate } def fixture_content(fixture) File.read(File.join(fixture_path, fixture)) end def parse_shared_content # Populate the YARD registry with both Puppet and Ruby source YARD::Parser::SourceParser.parse_string(fixture_content('puppet/class.pp'), :puppet) YARD::Parser::SourceParser.parse_string(fixture_content('puppet/function.pp'), :puppet) YARD::Parser::SourceParser.parse_string(fixture_content('ruby/func4x.rb'), :ruby) YARD::Parser::SourceParser.parse_string(fixture_content('ruby/func4x_1.rb'), :ruby) YARD::Parser::SourceParser.parse_string(fixture_content('ruby/func3x.rb'), :ruby) YARD::Parser::SourceParser.parse_string(fixture_content('ruby/func3x.rb'), :ruby) YARD::Parser::SourceParser.parse_string(fixture_content('ruby/provider.rb'), :ruby) YARD::Parser::SourceParser.parse_string(fixture_content('ruby/resource_type.rb'), :ruby) YARD::Parser::SourceParser.parse_string(fixture_content('ruby/resource_api.rb'), :ruby) # task metadata derives the task name from the filename, so we have to parse # directly from the filesystem to correctly pick up the name YARD::Parser::SourceParser.parse(File.join(fixture_path, 'json/backup.json')) end def parse_plan_content # the parser behaves differently when parsing puppet files in the the plans directory, # so we have to parse directly from the filesystem to correctly pick up the name YARD::Parser::SourceParser.parse(File.join(fixture_path, 'plans/plan.pp')) end def parse_data_type_content YARD::Parser::SourceParser.parse_string(fixture_content('ruby/data_type.rb'), :ruby) YARD::Parser::SourceParser.parse_string(fixture_content('puppet/type_alias.pp'), :puppet) end RSpec.shared_examples 'markdown lint checker' do |_parameter| it 'does not generate markdown lint errors from the rendered markdown' do expect(output).to have_no_markdown_lint_errors end end before do parse_shared_content end include_examples 'markdown lint checker' describe 'table of contents' do it 'includes links to public classes' do expect(output).to match(/\[`klass`\]\(#.*\).*simple class/i) end it 'includes links to private classes' do expect(output).to match(/`noparams`.*overview.*noparams/i) end it 'includes links to defined types' do expect(output).to match(/\[`klass::dt`\]\(#.*\).*simple defined type/i) end it 'includes links to resource types' do expect(output).to match(/\[`apt_key`\]\(#.*\).*resource type.*new api/i) expect(output).to match(/\[`database`\]\(#.*\).*example database.*type/i) end it 'includes links to functions' do expect(output).to match(/\[`func`\]\(#.*\).*simple puppet function/i) expect(output).to match(/\[`func3x`\]\(#.*\).*example 3\.x function/i) expect(output).to match(/\[`func4x`\]\(#.*\).*example 4\.x function/i) expect(output).to match(/\[`func4x_1`\]\(#.*\).*example 4\.x function.*one signature/i) end it 'includes links to tasks' do expect(output).to match(/\[`backup`\]\(#.*\).*backup your database/i) end end describe 'resource types' do it 'includes checks in parameter list for the database type' do expect(output).to match(/check to see if the database already exists/i) end end describe 'deprecated message' do it 'includes deprecated message' do expect(output).to match(/\*\*DEPRECATED\*\* No longer supported and will be removed in a future release/) end end describe 'with Puppet Plans', if: TEST_PUPPET_PLANS do before do parse_plan_content end include_examples 'markdown lint checker' describe 'table of contents' do it 'includes links to plans' do expect(output).to match(/\[`plann`\]\(#.*\).*simple plan/i) end end end describe 'with Puppet Data Types', if: TEST_PUPPET_DATATYPES do before do parse_data_type_content end include_examples 'markdown lint checker' describe 'table of contents' do it 'includes links to data types' do expect(output).to match(/\[`Amodule::ComplexAlias`\]\(#.*\).*Amodule::ComplexAlias/i) expect(output).to match(/\[`Amodule::SimpleAlias`\]\(#.*\).*Amodule::SimpleAlias/i) expect(output).to match(/\[`UnitDataType`\]\(#.*\).*data type in ruby/i) end end describe 'parameter docs' do it 'includes param name' do expect(output).to match(/#+ `param1`/) end it 'includes param type' do expect(output).to match(/Data type: `Variant\[Numeric, String\[1,2\]\]`/) end it 'includes param description' do expect(output).to match(/a variant parameter/i) end it 'includes param default' do expect(output).to match(/default value: `param2`/i) end end describe 'function docs' do it 'includes signature' do expect(output).to match(/UnitDataType\.func1\(param1, param2\)/) end it 'includes summary' do expect(output).to match(/func1 documentation/i) end it 'includes parameter docs' do expect(output).to match(/param1 documentation/i) end it 'includes return value' do expect(output).to match(/returns: `optional\[string\]`/i) end end end end it 'renders only private functions correctly' do expect(YARD::Parser::SourceParser.parse_string(<<~PUPPET, :puppet).enumerator.length).to eq(1) # @return void # @api private function func_private() {} PUPPET expect(described_class.generate).to eq(<<~MARKDOWN) # Reference ## Table of Contents ### Functions #### Private Functions * `func_private` MARKDOWN end it 'renders only public functions correctly' do expect(YARD::Parser::SourceParser.parse_string(<<~PUPPET, :puppet).enumerator.length).to eq(1) # @return void function func_public() {} PUPPET expect(described_class.generate).to eq(<<~MARKDOWN) # Reference ## Table of Contents ### Functions * [`func_public`](#func_public) ## Functions ### `func_public` Type: Puppet Language The func_public function. #### `func_public()` The func_public function. Returns: `Any` void MARKDOWN end it 'renders both public and private functions correctly' do expect(YARD::Parser::SourceParser.parse_string(<<~PUPPET, :puppet).enumerator.length).to eq(2) # @return void function func_public() {} # @return void # @api private function func_private() {} PUPPET expect(described_class.generate).to eq(<<~MARKDOWN) # Reference ## Table of Contents ### Functions #### Public Functions * [`func_public`](#func_public) #### Private Functions * `func_private` ## Functions ### `func_public` Type: Puppet Language The func_public function. #### `func_public()` The func_public function. Returns: `Any` void MARKDOWN end it 'renders single-line data types with inline code' do expect(YARD::Parser::SourceParser.parse_string(<<~PUPPET, :puppet).enumerator.length).to eq(1) # @summary it’s for testing type MyEnum = Enum[a, b] PUPPET expect(described_class.generate).to match(/^Alias of `Enum\[a, b\]`$/) end it 'renders multi-line data types with inline code' do expect(YARD::Parser::SourceParser.parse_string(<<~PUPPET, :puppet).enumerator.length).to eq(1) # summary Test Type # type Test_module::Test_type = Hash[ Pattern[/^[a-z][a-z0-9_-]*$/], Struct[ { param1 => String[1], param2 => Stdlib::Absolutepath, paramX => Boolean, } ] ] PUPPET expect(described_class.generate).to include(<<~MARKDOWN) Alias of ```puppet Hash[Pattern[/^[a-z][a-z0-9_-]*$/], Struct[ { param1 => String[1], param2 => Stdlib::Absolutepath, paramX => Boolean, } ]] ``` MARKDOWN end it 'renders single-line default values with inline code' do expect(YARD::Parser::SourceParser.parse_string(<<~PUPPET, :puppet).enumerator.length).to eq(1) # @summary Test class myclass ( String $os = 'linux', ) { } PUPPET expect(described_class.generate).to include(<<~MARKDOWN) Default value: `'linux'` MARKDOWN end it 'renders multi-line default values with a code block' do skip('Broken by https://tickets.puppetlabs.com/browse/PUP-11632') expect(YARD::Parser::SourceParser.parse_string(<<~PUPPET, :puppet).enumerator.length).to eq(1) # @summary Test class myclass ( String $os = $facts['kernel'] ? { 'Linux' => 'linux', 'Darwin' => 'darwin', default => $facts['kernel'], }, ) { } PUPPET expect(described_class.generate).to include(<<~MARKDOWN) Default value: ```puppet $facts['kernel'] ? { 'Linux' => 'linux', 'Darwin' => 'darwin', default => $facts['kernel'] } ``` MARKDOWN end end puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/000077500000000000000000000000001466634474300251765ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/code_objects/000077500000000000000000000000001466634474300276215ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/code_objects/task_spec.rb000066400000000000000000000060241466634474300321240ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard/code_objects/task' require 'puppet-strings/yard/parsers/json/task_statement' describe PuppetStrings::Yard::CodeObjects::Task do subject(:spec_subject) { described_class.new(statement) } let(:source) { <<~SOURCE } { "description": "Allows you to backup your database to local file.", "input_method": "stdin", "parameters": { "database": { "description": "Database to connect to", "type": "Optional[String[1]]" }, "user": { "description": "The user", "type": "Optional[String[1]]" }, "password": { "description": "The password", "type": "Optional[String[1]]" }, "sql": { "description": "Path to file you want backup to", "type": "String[1]" } } } SOURCE let(:json) { JSON.parse(source) } let(:statement) { PuppetStrings::Yard::Parsers::JSON::TaskStatement.new(json, source, 'test.json') } describe '#type' do it 'returns the correct type' do expect(spec_subject.type).to eq(:puppet_task) end end describe '#source' do it 'returns the source' do expect(spec_subject.source).to eq(source) end end describe '#to_hash' do let(:expected) do { name: 'test', supports_noop: false, docstring: { text: 'Allows you to backup your database to local file.', tags: [ { name: 'database', tag_name: 'param', text: 'Database to connect to', types: ['Optional[String[1]]'] }, { name: 'user', tag_name: 'param', text: 'The user', types: ['Optional[String[1]]'] }, { name: 'password', tag_name: 'param', text: 'The password', types: ['Optional[String[1]]'] }, { name: 'sql', tag_name: 'param', text: 'Path to file you want backup to', types: ['String[1]'] } ] }, file: 'test.json', input_method: 'stdin', line: 0, source: "{\n \"description\": \"Allows you to backup your database to local file.\",\n \"input_method\": \"stdin\",\n \"parameters\": {\n \"database\": {\n \"description\": \"Database to connect to\",\n \"type\": \"Optional[String[1]]\"\n },\n \"user\": {\n \"description\": \"The user\",\n \"type\": \"Optional[String[1]]\"\n },\n \"password\": {\n \"description\": \"The password\",\n \"type\": \"Optional[String[1]]\"\n },\n \"sql\": {\n \"description\": \"Path to file you want backup to\",\n \"type\": \"String[1]\"\n }\n }\n}\n" # rubocop:disable Layout/LineLength } end it 'returns the correct hash' do expect(spec_subject.to_hash).to eq(expected) end end end puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/000077500000000000000000000000001466634474300267765ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/json/000077500000000000000000000000001466634474300277475ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/json/task_handler_spec.rb000066400000000000000000000062301466634474300337460ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' describe PuppetStrings::Yard::Handlers::JSON::TaskHandler do subject(:spec_subject) do YARD::Parser::SourceParser.parse_string(source, :json) YARD::Registry.all(:puppet_task) end describe 'parsing task metadata with a syntax error' do let(:source) { <<~SOURCE } { "input_method": "stdin", "parameters": "database": { "description": "Database to connect to", "type": "Optional[String[1]]" } } } SOURCE it 'logs an error' do expect { spec_subject }.to output(/\[error\]: Failed to parse \(stdin\):/).to_stdout_from_any_process expect(spec_subject.empty?).to be(true) end end describe 'parsing task metadata with a missing description' do let(:source) { <<~SOURCE } { "input_method": "stdin", "parameters": { "database": { "description": "Database to connect to", "type": "Optional[String[1]]" }, "user": { "description": "The user", "type": "Optional[String[1]]" }, "password": { "description": "The password", "type": "Optional[String[1]]" }, "sql": { "description": "Path to file you want backup to", "type": "String[1]" } } } SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing a description for Puppet Task \(stdin\)/).to_stdout_from_any_process end end describe 'parsing task metadata with a description' do let(:source) { <<~SOURCE } { "description": "Allows you to backup your database to local file.", "input_method": "stdin", "parameters": { "database": { "description": "Database to connect to", "type": "Optional[String[1]]" }, "user": { "description": "The user", "type": "Optional[String[1]]" }, "password": { "description": "The password", "type": "Optional[String[1]]" }, "sql": { "description": "Path to file you want backup to", "type": "String[1]" } } } SOURCE it 'registers a task object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Task) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Tasks.instance) end end describe 'parsing task metadata with a missing parameter description' do let(:source) { <<~SOURCE } { "description": "Allows you to backup your database to local file.", "input_method": "stdin", "parameters": { "database": { "type": "Optional[String[1]]" } } } SOURCE it 'outputs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing description for param 'database' in Puppet Task \(stdin\)/).to_stdout_from_any_process end end end puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/puppet/000077500000000000000000000000001466634474300303135ustar00rootroot00000000000000class_handler_spec.rb000066400000000000000000000162261466634474300344040ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/puppet# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' describe PuppetStrings::Yard::Handlers::Puppet::ClassHandler do subject(:spec_subject) do YARD::Parser::SourceParser.parse_string(source, :puppet) YARD::Registry.all(:puppet_class) end describe 'parsing source without a class definition' do let(:source) { 'notice hi' } it 'no classes should be in the registry' do expect(spec_subject.empty?).to be(true) end end describe 'parsing source with a syntax error' do let(:source) { 'class foo{' } it 'logs an error' do expect { spec_subject }.to output(/\[error\]: Failed to parse \(stdin\): Syntax error at end of (file|input)/).to_stdout_from_any_process expect(spec_subject.empty?).to be(true) end end describe 'parsing a class with a missing docstring' do let(:source) { 'class foo{}' } it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing documentation for Puppet class 'foo' at \(stdin\):1\./).to_stdout_from_any_process end end describe 'parsing a class with a docstring' do let(:source) { <<~SOURCE } # A simple foo class. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. class foo(Integer $param1, $param2, String $param3 = hi) inherits foo::bar { file { '/tmp/foo': ensure => present } } SOURCE it 'registers a class object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Class) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Classes.instance) expect(object.name).to eq(:foo) expect(object.statement).not_to be_nil expect(object.parameters).to eq([['param1', nil], ['param2', nil], %w[param3 hi]]) expect(object.docstring).to eq('A simple foo class.') expect(object.docstring.tags.size).to eq(4) tags = object.docstring.tags(:param) expect(tags.size).to eq(3) expect(tags[0].name).to eq('param1') expect(tags[0].text).to eq('First param.') expect(tags[0].types).to eq(['Integer']) expect(tags[1].name).to eq('param2') expect(tags[1].text).to eq('Second param.') expect(tags[1].types).to eq(['Any']) expect(tags[2].name).to eq('param3') expect(tags[2].text).to eq('Third param.') expect(tags[2].types).to eq(['String']) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') end end describe 'parsing a class with a missing parameter' do let(:source) { <<~SOURCE } # A simple foo class. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. # @param param4 missing! class foo(Integer $param1, $param2, String $param3 = hi) inherits foo::bar { file { '/tmp/foo': ensure => present } } SOURCE it 'outputs a warning' do expect { spec_subject }.to output(/\[warn\]: The @param tag for parameter 'param4' has no matching parameter at \(stdin\):6\./).to_stdout_from_any_process end end describe 'parsing a class with a missing @param tag' do let(:source) { <<~SOURCE } # A simple foo class. # @param param1 First param. # @param param2 Second param. class foo(Integer $param1, $param2, String $param3 = hi) inherits foo::bar { file { '/tmp/foo': ensure => present } } SOURCE it 'outputs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing @param tag for parameter 'param3' near \(stdin\):4\./).to_stdout_from_any_process end end describe 'parsing a class with a typed parameter that also has a @param tag type which matches' do let(:source) { <<~SOURCE } # A simple foo class. # @param [Integer] param1 First param. # @param param2 Second param. # @param param3 Third param. class foo(Integer $param1, $param2, String $param3 = hi) inherits foo::bar { file { '/tmp/foo': ensure => present } } SOURCE it 'respects the type that was documented' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) tags = spec_subject.first.tags(:param) expect(tags.size).to eq(3) expect(tags[0].types).to eq(['Integer']) end end describe 'parsing a class with a typed parameter that also has a @param tag type which does not match' do let(:source) { <<~SOURCE } # A simple foo class. # @param [Boolean] param1 First param. # @param param2 Second param. # @param param3 Third param. class foo(Integer $param1, $param2, String $param3 = hi) inherits foo::bar { file { '/tmp/foo': ensure => present } } SOURCE it 'outputs a warning' do expect { spec_subject } .to output( /\[warn\]: The type of the @param tag for parameter 'param1' does not match the parameter type specification near \(stdin\):5: ignoring in favor of parameter type information./ ) .to_stdout_from_any_process end end describe 'parsing a class with a untyped parameter that also has a @param tag type' do let(:source) { <<~SOURCE } # A simple foo class. # @param param1 First param. # @param [Boolean] param2 Second param. # @param param3 Third param. class foo(Integer $param1, $param2, String $param3 = hi) inherits foo::bar { file { '/tmp/foo': ensure => present } } SOURCE it 'respects the type that was documented' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) tags = spec_subject.first.tags(:param) expect(tags.size).to eq(3) expect(tags[1].types).to eq(['Boolean']) end end describe 'parsing a class with a summary' do context 'when the summary has fewer than 140 characters' do let(:source) { <<~SOURCE } # A simple foo class. # @summary A short summary. class foo() { file { '/tmp/foo': ensure => present } } SOURCE it 'parses the summary' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) summary = spec_subject.first.tags(:summary) expect(summary.first.text).to eq('A short summary.') end end context 'when the summary has more than 140 characters' do let(:source) { <<~SOURCE } # A simple foo class. # @summary A short summary that is WAY TOO LONG. AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH this is not what a summary is for! It should be fewer than 140 characters!! class foo() { file { '/tmp/foo': ensure => present } } SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: The length of the summary for puppet_class 'foo' exceeds the recommended limit of 140 characters./).to_stdout_from_any_process end end end end data_type_alias_handler_spec.rb000066400000000000000000000043761466634474300364250ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/puppet# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' describe PuppetStrings::Yard::Handlers::Puppet::DataTypeAliasHandler, if: TEST_PUPPET_DATATYPES do subject(:spec_subject) do YARD::Parser::SourceParser.parse_string(source, :puppet) YARD::Registry.all(:puppet_data_type_alias) end describe 'parsing source without a type alias definition' do let(:source) { 'notice hi' } it 'no aliases should be in the registry' do expect(spec_subject.empty?).to be(true) end end describe 'parsing source with a syntax error' do let(:source) { 'type Testype =' } it 'logs an error' do expect { spec_subject }.to output(/\[error\]: Failed to parse \(stdin\): Syntax error at end of (file|input)/).to_stdout_from_any_process expect(spec_subject.empty?).to be(true) end end describe 'parsing a data type alias with a missing docstring' do let(:source) { 'type Testype = String[1]' } it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing documentation for Puppet type alias 'Testype' at \(stdin\):1\./).to_stdout_from_any_process end end describe 'parsing a data type alias with a summary' do context 'when the summary has fewer than 140 characters' do let(:source) { <<~SOURCE } # A simple foo type. # @summary A short summary. type Testype = String[1] SOURCE it 'parses the summary' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) summary = spec_subject.first.tags(:summary) expect(summary.first.text).to eq('A short summary.') end end context 'when the summary has more than 140 characters' do let(:source) { <<~SOURCE } # A simple foo type. # @summary A short summary that is WAY TOO LONG. AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH this is not what a summary is for! It should be fewer than 140 characters!! type Testype = String[1] SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: The length of the summary for puppet_data_type_alias 'Testype' exceeds the recommended limit of 140 characters./).to_stdout_from_any_process end end end end defined_type_handler_spec.rb000066400000000000000000000175451466634474300357430ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/puppet# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' describe PuppetStrings::Yard::Handlers::Puppet::DefinedTypeHandler do subject(:spec_subject) do YARD::Parser::SourceParser.parse_string(source, :puppet) YARD::Registry.all(:puppet_defined_type) end describe 'parsing source without a defined type definition' do let(:source) { 'notice hi' } it 'no defined types should be in the registry' do expect(spec_subject.empty?).to be(true) end end describe 'parsing source with a syntax error' do let(:source) { 'define foo{' } it 'logs an error' do expect { spec_subject }.to output(/\[error\]: Failed to parse \(stdin\): Syntax error at end of (file|input)/).to_stdout_from_any_process expect(spec_subject.empty?).to be(true) end end describe 'parsing a defined type with a missing docstring' do let(:source) { 'define foo{}' } it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing documentation for Puppet defined type 'foo' at \(stdin\):1\./).to_stdout_from_any_process end end describe 'parsing a defined type with a docstring' do let(:source) { <<~SOURCE } # A simple foo defined type. # @param name The type name. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. define foo(Integer $param1, $param2, String $param3 = hi) { file { '/tmp/foo': ensure => present } } SOURCE it 'does not output a warning for title/name' do expect { spec_subject }.not_to output(/\[warn\].*(name|title).*/).to_stdout_from_any_process end it 'registers a defined type object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DefinedType) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::DefinedTypes.instance) expect(object.name).to eq(:foo) expect(object.statement).not_to be_nil expect(object.parameters).to eq([['param1', nil], ['param2', nil], %w[param3 hi]]) expect(object.docstring).to eq('A simple foo defined type.') expect(object.docstring.tags.size).to eq(5) tags = object.docstring.tags(:param) expect(tags.size).to eq(4) expect(tags[0].name).to eq('name') expect(tags[0].text).to eq('The type name.') expect(tags[0].types).to be_nil expect(tags[1].name).to eq('param1') expect(tags[1].text).to eq('First param.') expect(tags[1].types).to eq(['Integer']) expect(tags[2].name).to eq('param2') expect(tags[2].text).to eq('Second param.') expect(tags[2].types).to eq(['Any']) expect(tags[3].name).to eq('param3') expect(tags[3].text).to eq('Third param.') expect(tags[3].types).to eq(['String']) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') end end describe 'parsing a defined type with a missing parameter' do let(:source) { <<~SOURCE } # A simple foo defined type. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. # @param param4 missing! define foo(Integer $param1, $param2, String $param3 = hi) { file { '/tmp/foo': ensure => present } } SOURCE it 'outputs a warning' do expect { spec_subject }.to output(/\[warn\]: The @param tag for parameter 'param4' has no matching parameter at \(stdin\):6\./).to_stdout_from_any_process end end describe 'parsing a defined type with a missing @param tag' do let(:source) { <<~SOURCE } # A simple foo defined type. # @param param1 First param. # @param param2 Second param. define foo(Integer $param1, $param2, String $param3 = hi) { file { '/tmp/foo': ensure => present } } SOURCE it 'outputs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing @param tag for parameter 'param3' near \(stdin\):4\./).to_stdout_from_any_process end end describe 'parsing a defined type with a typed parameter that also has a @param tag type which matches' do let(:source) { <<~SOURCE } # A simple foo defined type. # @param [Integer] param1 First param. # @param param2 Second param. # @param param3 Third param. define foo(Integer $param1, $param2, String $param3 = hi) { file { '/tmp/foo': ensure => present } } SOURCE it 'respects the type that was documented' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) tags = spec_subject.first.tags(:param) expect(tags.size).to eq(3) expect(tags[0].types).to eq(['Integer']) end end describe 'parsing a defined type with a typed parameter that also has a @param tag type which does not match' do let(:source) { <<~SOURCE } # A simple foo defined type. # @param [Boolean] param1 First param. # @param param2 Second param. # @param param3 Third param. define foo(Integer $param1, $param2, String $param3 = hi) { file { '/tmp/foo': ensure => present } } SOURCE it 'outputs a warning' do expect { spec_subject } .to output(/\[warn\]: The type of the @param tag for parameter 'param1' does not match the parameter type specification near \(stdin\):5: ignoring in favor of parameter type information./) .to_stdout_from_any_process end end describe 'parsing a defined type with a untyped parameter that also has a @param tag type' do let(:source) { <<~SOURCE } # A simple foo defined type. # @param param1 First param. # @param [Boolean] param2 Second param. # @param param3 Third param. define foo(Integer $param1, $param2, String $param3 = hi) { file { '/tmp/foo': ensure => present } } SOURCE it 'respects the type that was documented' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) tags = spec_subject.first.tags(:param) expect(tags.size).to eq(3) expect(tags[1].types).to eq(['Boolean']) end end describe 'parsing a defined type with a summary' do context 'when the summary has fewer than 140 characters' do let(:source) { <<~SOURCE } # A simple foo defined type. # @summary A short summary. # @param param1 First param. # @param [Boolean] param2 Second param. # @param param3 Third param. define foo(Integer $param1, $param2, String $param3 = hi) { file { '/tmp/foo': ensure => present } } SOURCE it 'parses the summary' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) summary = spec_subject.first.tags(:summary) expect(summary.first.text).to eq('A short summary.') end end context 'when the summary has more than 140 characters' do let(:source) { <<~SOURCE } # A simple foo defined type. # @summary A short summary that is WAY TOO LONG. AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH this is not what a summary is for! It should be fewer than 140 characters!! # @param param1 First param. # @param [Boolean] param2 Second param. # @param param3 Third param. define foo(Integer $param1, $param2, String $param3 = hi) { file { '/tmp/foo': ensure => present } } SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: The length of the summary for puppet_defined_type 'foo' exceeds the recommended limit of 140 characters./).to_stdout_from_any_process end end end end function_handler_spec.rb000066400000000000000000000277221466634474300351270ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/puppet# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' # Limit this spec to Puppet 4.1+ (when functions in Puppet were implemented) describe PuppetStrings::Yard::Handlers::Puppet::FunctionHandler, if: TEST_PUPPET_FUNCTIONS do subject(:spec_subject) do YARD::Parser::SourceParser.parse_string(source, :puppet) YARD::Registry.all(:puppet_function) end describe 'parsing source without a function definition' do let(:source) { 'notice hi' } it 'no functions should be in the registry' do expect(spec_subject.empty?).to be(true) end end describe 'parsing source with a syntax error' do let(:source) { 'function foo{' } it 'logs an error' do expect { spec_subject }.to output(/\[error\]: Failed to parse \(stdin\): Syntax error at end of/).to_stdout_from_any_process expect(spec_subject.empty?).to be(true) end end describe 'parsing a function with a missing docstring' do let(:source) { 'function foo{}' } it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing documentation for Puppet function 'foo' at \(stdin\):1\./).to_stdout_from_any_process end end describe 'parsing a function with a docstring' do let(:source) { <<~SOURCE } # A simple foo function. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. # @return [Undef] Returns nothing. function foo(Integer $param1, $param2, String $param3 = hi) { notice 'hello world' undef } SOURCE it 'registers a function object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Functions.instance(PuppetStrings::Yard::CodeObjects::Function::PUPPET)) expect(object.name).to eq(:foo) expect(object.signature).to eq('foo(Integer $param1, Any $param2, String $param3 = hi)') expect(object.parameters).to eq([['param1', nil], ['param2', nil], %w[param3 hi]]) expect(object.docstring).to eq('A simple foo function.') expect(object.docstring.tags.size).to eq(5) tags = object.docstring.tags(:param) expect(tags.size).to eq(3) expect(tags[0].name).to eq('param1') expect(tags[0].text).to eq('First param.') expect(tags[0].types).to eq(['Integer']) expect(tags[1].name).to eq('param2') expect(tags[1].text).to eq('Second param.') expect(tags[1].types).to eq(['Any']) expect(tags[2].name).to eq('param3') expect(tags[2].text).to eq('Third param.') expect(tags[2].types).to eq(['String']) tags = object.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].tag_name).to eq('return') expect(tags[0].text).to eq('Returns nothing.') expect(tags[0].types).to eq(['Undef']) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') end end describe 'parsing a function with a missing parameter' do let(:source) { <<~SOURCE } # A simple foo function. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. # @param param4 missing! # @return [Undef] Returns nothing. function foo(Integer $param1, $param2, String $param3 = hi) { notice 'hello world' } SOURCE it 'outputs a warning' do expect { spec_subject } .to output(/\[warn\]: The @param tag for parameter 'param4' has no matching parameter at \(stdin\):7\./) .to_stdout_from_any_process end end describe 'parsing a function with a missing @param tag' do let(:source) { <<~SOURCE } # A simple foo function. # @param param1 First param. # @param param2 Second param. # @return [Undef] Returns nothing. function foo(Integer $param1, $param2, String $param3 = hi) { notice 'hello world' } SOURCE it 'outputs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing @param tag for parameter 'param3' near \(stdin\):5\./).to_stdout_from_any_process end end describe 'parsing a function with a typed parameter that also has a @param tag type which matches' do let(:source) { <<~SOURCE } # A simple foo function. # @param [Integer] param1 First param. # @param param2 Second param. # @param param3 Third param. # @return [Undef] Returns nothing. function foo(Integer $param1, $param2, String $param3 = hi) { notice 'hello world' } SOURCE it 'respects the type that was documented' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) tags = spec_subject.first.tags(:param) expect(tags.size).to eq(3) expect(tags[0].types).to eq(['Integer']) end end describe 'parsing a function with a typed parameter that also has a @param tag type which does not match' do let(:source) { <<~SOURCE } # A simple foo function. # @param [Boolean] param1 First param. # @param param2 Second param. # @param param3 Third param. # @return [Undef] Returns nothing. function foo(Integer $param1, $param2, String $param3 = hi) { notice 'hello world' } SOURCE it 'outputs a warning' do expect { spec_subject } .to output( /\[warn\]: The type of the @param tag for parameter 'param1' does not match the parameter type specification near \(stdin\):6: ignoring in favor of parameter type information./ ) .to_stdout_from_any_process end end describe 'parsing a function with a untyped parameter that also has a @param tag type' do let(:source) { <<~SOURCE } # A simple foo function. # @param param1 First param. # @param [Boolean] param2 Second param. # @param param3 Third param. # @return [Undef] Returns nothing. function foo(Integer $param1, $param2, String $param3 = hi) { notice 'hello world' } SOURCE it 'respects the type that was documented' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) tags = spec_subject.first.tags(:param) expect(tags.size).to eq(3) expect(tags[1].types).to eq(['Boolean']) end end describe 'parsing a function with a missing @return tag' do let(:source) { <<~SOURCE } # A simple foo function. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. function foo(Integer $param1, $param2, String $param3 = hi) { notice 'hello world' } SOURCE it 'outputs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing @return tag near \(stdin\):5\./).to_stdout_from_any_process end end describe 'parsing a function with a missing @return tag and return type specified in the function definition', if: TEST_FUNCTION_RETURN_TYPE do let(:source) { <<~SOURCE } # A simple foo function. function foo() >> String { notice 'hello world' } SOURCE it 'registers a function object with the correct return type' do expect { spec_subject }.to output(/\[warn\]: Missing @return tag near \(stdin\):2\./).to_stdout_from_any_process expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) tags = object.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].tag_name).to eq('return') expect(tags[0].text).to eq('') expect(tags[0].types).to eq(['String']) end end describe 'parsing a function with a non-conflicting return tag and type in function definition', if: TEST_FUNCTION_RETURN_TYPE do let(:source) { <<~SOURCE } # A simple foo function # @return [String] Hi there function foo() >> String { notice 'hi there' } SOURCE it 'does not output a warning if return types match' do expect { spec_subject }.not_to output(/Documented return type does not match return type in function definition/).to_stdout_from_any_process end end describe 'parsing a function with a conflicting return tag and type in function definition', if: TEST_FUNCTION_RETURN_TYPE do let(:source) { <<~SOURCE } # A simple foo function. # @return [Integer] this is a lie. function foo() >> Struct[{'a' => Integer[1, 10]}] { notice 'hello world' } SOURCE it 'prefers the return type from the function definition' do expect { spec_subject }.to output(/\[warn\]: Documented return type does not match return type in function definition near \(stdin\):3\./).to_stdout_from_any_process expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) tags = object.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].tag_name).to eq('return') expect(tags[0].text).to eq('this is a lie.') expect(tags[0].types).to eq(["Struct[{'a' => Integer[1, 10]}]"]) end end describe 'parsing a function with return tag without type', if: TEST_FUNCTION_RETURN_TYPE do let(:source) { <<~SOURCE } # A simple foo function. # @return This is something. function foo() >> Struct[{'a' => Integer[1, 10]}] { notice 'hello world' } SOURCE it 'gets the return type from the function definition' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) tags = object.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].tag_name).to eq('return') expect(tags[0].text).to eq('This is something.') expect(tags[0].types).to eq(["Struct[{'a' => Integer[1, 10]}]"]) end end describe 'parsing a function without a return tag or return type in the function definition' do let(:source) { <<~SOURCE } # A simple foo function. function foo() { notice 'hello world' } SOURCE it 'adds a return tag with a default type value of Any' do expect { spec_subject }.to output(/\[warn\]: Missing @return tag near \(stdin\):2\./).to_stdout_from_any_process expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) tags = object.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].tag_name).to eq('return') expect(tags[0].text).to eq('') expect(tags[0].types).to eq(['Any']) end end describe 'parsing a function with a summary' do context 'when the summary has fewer than 140 characters' do let(:source) { <<~SOURCE } # A simple foo function. # @summary A short summary. # @return [String] foo function foo() { notice 'hello world' } SOURCE it 'parses the summary' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) summary = spec_subject.first.tags(:summary) expect(summary.first.text).to eq('A short summary.') end end context 'when the summary has more than 140 characters' do let(:source) { <<~SOURCE } # A simple foo function. # @summary A short summary that is WAY TOO LONG. AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH this is not what a summary is for! It should be fewer than 140 characters!! function foo() { notice 'hello world' } SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: The length of the summary for puppet_function 'foo' exceeds the recommended limit of 140 characters./).to_stdout_from_any_process end end end end puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/ruby/000077500000000000000000000000001466634474300277575ustar00rootroot00000000000000data_type_handler_spec.rb000066400000000000000000000535131466634474300347150ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/ruby# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' describe PuppetStrings::Yard::Handlers::Ruby::DataTypeHandler, if: TEST_PUPPET_DATATYPES do subject(:spec_subject) do YARD::Parser::SourceParser.parse_string(source, :ruby) YARD::Registry.all(:puppet_data_type) end # Tests may suppress logging to make it easier to read results, # so remember the logging object prior to running the test. original_yard_logging_object = YARD::Logger.instance.io after do # Restore the original logging IO object YARD::Logger.instance.io = original_yard_logging_object end def suppress_yard_logging YARD::Logger.instance.io = nil end describe 'parsing source without a data type definition' do let(:source) { 'puts "hi"' } it 'no data types should be in the registry' do expect(spec_subject.empty?).to be(true) end end describe 'parsing an empty data type definition' do let(:source) { <<~SOURCE } Puppet::DataTypes.create_type('RubyDataType') do end SOURCE it 'registers a data type object with no param tags or functions' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::DataTypes.instance) expect(object.name).to eq(:RubyDataType) expect(object.docstring).to eq('') expect(object.docstring.tags.size).to eq(1) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') expect(object.parameters.size).to eq(0) expect(object.functions.size).to eq(0) end end describe 'parsing a data type definition with missing param tags' do let(:source) { <<~SOURCE } # An example Puppet Data Type in Ruby. Puppet::DataTypes.create_type('RubyDataType') do interface <<~'PUPPET' attributes => { msg => String[1], } PUPPET end SOURCE it 'outputs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing @param tag for attribute 'msg' near \(stdin\):2/).to_stdout_from_any_process end it 'registers a data type object with all param tags' do suppress_yard_logging expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::DataTypes.instance) expect(object.name).to eq(:RubyDataType) expect(object.docstring).to eq('An example Puppet Data Type in Ruby.') expect(object.docstring.tags.size).to eq(2) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') # Check that the param tags are created tags = object.docstring.tags(:param) expect(tags.size).to eq(1) expect(tags[0].name).to eq('msg') expect(tags[0].text).to eq('') expect(tags[0].types).to eq(['String[1]']) # Check for default values for parameters expect(object.parameters.size).to eq(1) expect(object.parameters[0]).to eq(['msg', nil]) end end describe 'parsing a data type definition with missing function' do context 'which has parameters' do let(:source) { <<~SOURCE } # An example Puppet Data Type in Ruby. Puppet::DataTypes.create_type('RubyDataType') do interface <<~'PUPPET' functions => { func1 => Callable[[Integer, String], String] } PUPPET end SOURCE it 'outputs a warning about the missing functions' do expect { spec_subject }.to output(/\[warn\]: Missing @!method tag for function 'func1' near \(stdin\):2/m).to_stdout_from_any_process end it 'registers a data type object with all functions' do suppress_yard_logging expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::DataTypes.instance) expect(object.name).to eq(:RubyDataType) expect(object.docstring).to eq('An example Puppet Data Type in Ruby.') expect(object.docstring.tags.size).to eq(1) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') # Check for functions expect(object.functions.size).to eq(1) func = object.functions.first expect(func.docstring).to eq('') expect(func.signature).to eq('RubyDataType.func1(param1, param2)') expect(func.tag(:return)).not_to be_nil expect(func.tag(:return).types).to eq(['String']) param_tags = func.docstring.tags(:param) expect(param_tags.size).to eq(2) expect(param_tags[0].name).to eq('param1') expect(param_tags[0].text).to eq('') expect(param_tags[0].types).to eq(['Integer']) expect(param_tags[1].name).to eq('param2') expect(param_tags[1].text).to eq('') expect(param_tags[1].types).to eq(['String']) end context 'which has multiple functions' do let(:source) { <<~SOURCE } # An example Puppet Data Type in Ruby. Puppet::DataTypes.create_type('RubyDataType') do interface <<~'PUPPET' functions => { func1 => Callable[[], String], func2 => Callable[[Integer], String] } PUPPET end SOURCE it 'outputs a warning about the first missing function' do expect { spec_subject }.to output(/\[warn\]: Missing @!method tag for function 'func1' near \(stdin\):2/m).to_stdout_from_any_process end it 'outputs a warning about the second missing function' do expect { spec_subject }.to output(/\[warn\]: Missing @!method tag for function 'func2' near \(stdin\):2/m).to_stdout_from_any_process end it 'registers a data type object with all functions' do suppress_yard_logging expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType) # Check for functions expect(object.functions.size).to eq(2) # A function with no parmeters func = object.functions.first expect(func.signature).to eq('RubyDataType.func1') expect(func.tag(:return).types).to eq(['String']) param_tags = func.docstring.tags(:param) expect(param_tags).to be_empty # A function with one parmeter func = object.functions.last expect(func.signature).to eq('RubyDataType.func2(param1)') expect(func.tag(:return).types).to eq(['String']) param_tags = func.docstring.tags(:param) expect(param_tags.size).to eq(1) end end end end describe 'parsing a data type definition with extra tags' do let(:source) { <<~SOURCE } # An example Puppet Data Type in Ruby. # @param msg A message parameter. # @param arg1 Optional String parameter. Defaults to 'param'. # # @!method does_not_exist # Puppet::DataTypes.create_type('RubyDataType') do interface <<~'PUPPET' attributes => { msg => Numeric, }, functions => { func1 => Callable[[], Optional[String]] } PUPPET end SOURCE it 'outputs a warning about the extra attribute' do expect { spec_subject }.to output(/\[warn\]: The @param tag for 'arg1' has no matching attribute near \(stdin\):7/m).to_stdout_from_any_process end it 'outputs a warning about the extra function' do expect { spec_subject }.to output(/\[warn\]: The @!method tag for 'does_not_exist' has no matching function definition near \(stdin\):7/m).to_stdout_from_any_process end it 'registers a data type object with extra information removed' do suppress_yard_logging expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::DataTypes.instance) expect(object.name).to eq(:RubyDataType) expect(object.docstring).to eq('An example Puppet Data Type in Ruby.') expect(object.docstring.tags.size).to eq(2) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') # Check that the extra param tags are removed tags = object.docstring.tags(:param) expect(tags.size).to eq(1) expect(tags[0].name).to eq('msg') expect(tags[0].text).to eq('A message parameter.') expect(tags[0].types).to eq(['Numeric']) # Check that only the actual attributes appear expect(object.parameters.size).to eq(1) expect(object.parameters[0]).to eq(['msg', nil]) # Check that the extra functions are removed meths = object.meths expect(meths.size).to eq(1) expect(meths[0].name).to eq(:func1) end end describe 'parsing a valid data type definition' do # TODO: What about testing for `type_parameters => {}` # e.g. https://github.com/puppetlabs/puppet/blob/main/lib/puppet/datatypes/error.rb let(:source) { <<~SOURCE } # An example Puppet Data Type in Ruby. # # @param msg A message parameter5. # @param arg1 Optional String parameter5. Defaults to 'param'. # # @!method func1(foo, bar) # func1 documentation # @param [String] foo foo documentation # @param [Integer] bar bar documentation # @return [Optional[String]] # Puppet::DataTypes.create_type('RubyDataType') do interface <<~'PUPPET' attributes => { msg => Variant[Numeric, String[1,2]], arg1 => { type => Optional[String[1]], value => "param" } }, functions => { func1 => Callable[[String, Integer], Optional[String]] } PUPPET end SOURCE it 'registers a data type object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::DataTypes.instance) expect(object.name).to eq(:RubyDataType) expect(object.docstring).to eq('An example Puppet Data Type in Ruby.') expect(object.docstring.tags.size).to eq(3) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') # Check that the param tags are set tags = object.docstring.tags(:param) expect(tags.size).to eq(2) expect(tags[0].name).to eq('msg') expect(tags[0].text).to eq('A message parameter5.') expect(tags[0].types).to eq(['Variant[Numeric, String[1,2]]']) expect(tags[1].name).to eq('arg1') expect(tags[1].text).to eq('Optional String parameter5. Defaults to \'param\'.') expect(tags[1].types).to eq(['Optional[String[1]]']) # Check for default values expect(object.parameters.size).to eq(2) expect(object.parameters[0]).to eq(['msg', nil]) expect(object.parameters[1]).to eq(%w[arg1 param]) # Check for functions expect(object.functions.size).to eq(1) func = object.functions.first expect(func.name).to eq(:func1) expect(func.docstring).to eq('func1 documentation') expect(func.tag(:return)).not_to be_nil expect(func.tag(:return).types).to eq(['Optional[String]']) param_tags = func.docstring.tags(:param) expect(param_tags.size).to eq(2) expect(param_tags[0].name).to eq('foo') expect(param_tags[0].text).to eq('foo documentation') expect(param_tags[0].types).to eq(['String']) expect(param_tags[1].name).to eq('bar') expect(param_tags[1].text).to eq('bar documentation') expect(param_tags[1].types).to eq(['Integer']) end context 'with multiple interfaces' do let(:source) { <<~SOURCE } # An example Puppet Data Type in Ruby. # # @param msg A message parameter5. # @param arg1 Optional String parameter5. Defaults to 'param'. # # @!method func1(param1, param2) # func1 documentation # @param [String] param1 param1 documentation # @param [Integer] param2 param2 documentation # @return [Optional[String]] # Puppet::DataTypes.create_type('RubyDataType') do if 1 == 2 interface <<~'PUPPET' This interface is invalid because of this text! attributes => { msg1 => Variant[Numeric, String[1,2]], }, functions => { func1 => Callable[[String, Integer], Optional[String]] } PUPPET elsif 1 == 3 interface <<~'PUPPET' attributes => { msg2 => Variant[Numeric, String[1,2]], }, functions => { func2 => Callable[[String, Integer], Optional[String]] } PUPPET else interface <<~'PUPPET' attributes => { msg3 => Variant[Numeric, String[1,2]], }, functions => { func3 => Callable[[String, Integer], Optional[String]] } PUPPET end end SOURCE it 'registers only the first valid interface' do suppress_yard_logging expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.name).to eq(:RubyDataType) # Check that the param tags are set tags = object.docstring.tags(:param) expect(tags.size).to eq(1) expect(tags[0].name).to eq('msg2') # Check for functions expect(object.functions.size).to eq(1) expect(object.functions.first.name).to eq(:func2) end end context 'with missing, partial and addition function parameters' do let(:source) { <<~SOURCE } # An example Puppet Data Type in Ruby. # # @!method func1(foo1, foo2) # func1 docs # @param [String] foo1 param1 documentation # @param [Integer] missing docs should exist # @param [String] extra Should not exist # @return [Integer] This is wrong # # @!method func2(param1, param2) # func2 docs - missing a parameter # @param [String] param1 param1 documentation # Puppet::DataTypes.create_type('RubyDataType') do interface <<~'PUPPET' attributes => { }, functions => { func1 => Callable[[Integer, Integer], Optional[String]], func2 => Callable[[Integer, Integer], Optional[String]] } PUPPET end SOURCE it 'outputs a warning about the incorrect return type' do expect { spec_subject }.to output(/\[warn\]: The @return tag for 'func1' has a different type definition .+ Expected \["Optional\[String\]"\]/m).to_stdout_from_any_process end it 'outputs a warning about the additional parameter' do expect { spec_subject }.to output(/\[warn\]: The @param tag for 'extra' should not exist for function 'func1' that is defined near/m).to_stdout_from_any_process end it 'outputs a warning about the wrong parameter type (func1)' do expect do spec_subject end.to output(/\[warn\]: The @param tag for 'foo1' for function 'func1' has a different type definition than the actual function near .+ Expected \["Integer"\]/m).to_stdout_from_any_process end it 'outputs a warning about the wrong parameter type (func2)' do expect do spec_subject end.to output(/\[warn\]: The @param tag for 'param1' for function 'func2' has a different type definition than the actual function near .+ Expected \["Integer"\]/m).to_stdout_from_any_process end it 'automatically fixes function parameters, except for differring types' do suppress_yard_logging expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType) # Check for functions expect(object.functions.size).to eq(2) func = object.functions.first expect(func.docstring).to eq('func1 docs') expect(func.tag(:return)).not_to be_nil expect(func.tag(:return).types).to eq(['Optional[String]']) param_tags = func.docstring.tags(:param) expect(param_tags.size).to eq(2) expect(param_tags[0].name).to eq('foo1') expect(param_tags[0].text).to eq('param1 documentation') expect(param_tags[0].types).to eq(['Integer']) expect(param_tags[1].name).to eq('missing') expect(param_tags[1].text).to eq('docs should exist') expect(param_tags[1].types).to eq(['Integer']) func = object.functions.last expect(func.docstring).to eq('func2 docs - missing a parameter') param_tags = func.docstring.tags(:param) expect(param_tags.size).to eq(2) expect(param_tags[0].name).to eq('param1') expect(param_tags[0].text).to eq('param1 documentation') expect(param_tags[0].types).to eq(['Integer']) expect(param_tags[1].name).to eq('param2') expect(param_tags[1].text).to eq('') expect(param_tags[1].types).to eq(['Integer']) end end end [ { value: '-1', expected: -1 }, { value: '0', expected: 0 }, { value: '10', expected: 10 }, { value: '0777', expected: 511 }, { value: '0xFF', expected: 255 }, { value: '0.1', expected: 0.1 }, { value: '31.415e-1', expected: 3.1415 }, { value: '0.31415e1', expected: 3.1415 } ].each do |testcase| describe "parsing a valid data type definition with numeric default #{testcase[:value]}" do let(:source) { <<~SOURCE } # An example Puppet Data Type in Ruby. # @param num1 A numeric parameter Puppet::DataTypes.create_type('RubyDataType') do interface <<~'PUPPET' attributes => { num1 => { type => Numeric, value => #{testcase[:value]} }, } PUPPET end SOURCE it 'registers a data type object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType) expect(object.parameters.size).to eq(1) expect(object.parameters[0]).to eq(['num1', testcase[:expected]]) end end end describe 'parsing an invalid data type definition' do let(:source) { <<~SOURCE } # The msg attribute is missing a comma. # # @param msg A message parameter5. # @param arg1 Optional String parameter5. Defaults to 'param'. Puppet::DataTypes.create_type('RubyDataType') do interface <<~'PUPPET' attributes => { msg => Variant[Numeric, String[1,2]] arg1 => { type => Optional[String[1]], value => "param" } }, functions => { func1 => Callable[[], Integer] } PUPPET end SOURCE it 'registers a partial data type object' do suppress_yard_logging expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::DataTypes.instance) expect(object.name).to eq(:RubyDataType) expect(object.docstring).to eq('The msg attribute is missing a comma.') # The attributes will be missing therefore only one tag expect(object.docstring.tags.size).to eq(1) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') # Check that the param tags are removed tags = object.docstring.tags(:param) expect(tags.size).to eq(0) # Check for default values expect(object.parameters.size).to eq(0) # Check for functions expect(object.functions.size).to eq(0) end it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: Invalid datatype definition at (.+):[0-9]+: Syntax error at 'arg1'/).to_stdout_from_any_process end end describe 'parsing a data type with a summary' do context 'when the summary has fewer than 140 characters' do let(:source) { <<~SOURCE } # An example Puppet Data Type in Ruby. # # @summary A short summary. Puppet::DataTypes.create_type('RubyDataType') do interface <<~'PUPPET' attributes => { } PUPPET end SOURCE it 'parses the summary' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) summary = spec_subject.first.tags(:summary) expect(summary.first.text).to eq('A short summary.') end end context 'when the summary has more than 140 characters' do let(:source) { <<~SOURCE } # An example Puppet Data Type in Ruby. # # @summary A short summary that is WAY TOO LONG. AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH this is not what a summary is for! It should be fewer than 140 characters!! Puppet::DataTypes.create_type('RubyDataType') do interface <<~'PUPPET' attributes => { } PUPPET end SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: The length of the summary for puppet_data_type 'RubyDataType' exceeds the recommended limit of 140 characters./).to_stdout_from_any_process end end end end function_handler_spec.rb000066400000000000000000000732211466634474300345660ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/ruby# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' describe PuppetStrings::Yard::Handlers::Ruby::FunctionHandler do subject(:spec_subject) do YARD::Parser::SourceParser.parse_string(source, :ruby) YARD::Registry.all(:puppet_function) end describe 'parsing source without a function definition' do let(:source) { 'puts "hi"' } it 'no functions should be in the registry' do expect(spec_subject.empty?).to be(true) end end describe 'parsing 3.x API functions' do describe 'parsing a function with a missing docstring' do let(:source) { <<~SOURCE } Puppet::Parser::Functions.newfunction(:foo) do |*args| end SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing documentation for Puppet function 'foo' at \(stdin\):1\./).to_stdout_from_any_process end end describe 'parsing a function with a doc parameter' do # Bug: Putting `) do |*args|` on the first line rather than right after # the end of the heredoc block causes the docstring to be trimmed. This is # probably related to https://github.com/lsegal/yard/issues/779. The code # in PuppetStrings::Yard::Handlers::Ruby::Base has a special work around # for this, but it seems to be limited by how much data YARD provides, and # it often isn’t enough. # # Given that this occurs only in old-style functions, it’s probably not # worth pursuing. let(:source) { <<~SOURCE } Puppet::Parser::Functions.newfunction(:foo, doc: <<~'DOC' An example 3.x function. @param [String] first The first parameter. @param second The second parameter. @return [Undef] Returns nothing. DOC ) do |*args| # ... end SOURCE it 'registers a function object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Functions.instance(PuppetStrings::Yard::CodeObjects::Function::RUBY_3X)) expect(object.name).to eq(:foo) expect(object.signature).to eq('foo(String $first, Any $second)') expect(object.parameters).to eq([['first', nil], ['second', nil]]) expect(object.docstring).to eq('An example 3.x function.') expect(object.docstring.tags.size).to eq(4) tags = object.docstring.tags(:param) expect(tags.size).to eq(2) expect(tags[0].name).to eq('first') expect(tags[0].text).to eq('The first parameter.') expect(tags[0].types).to eq(['String']) expect(tags[1].name).to eq('second') expect(tags[1].text).to eq('The second parameter.') expect(tags[1].types).to eq(['Any']) tags = object.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].name).to be_nil expect(tags[0].text).to eq('Returns nothing.') expect(tags[0].types).to eq(['Undef']) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') end end describe 'parsing a function with a doc parameter which has a newline between the namespace and the newfunction call' do # Bug: Putting `) do |*args|` on the first line rather than right after # the end of the heredoc block causes the docstring to be trimmed. This is # probably related to https://github.com/lsegal/yard/issues/779. The code # in PuppetStrings::Yard::Handlers::Ruby::Base has a special work around # for this, but it seems to be limited by how much data YARD provides, and # it often isn’t enough. # # Given that this occurs only in old-style functions, it’s probably not # worth pursuing. let(:source) { <<~SOURCE } module Puppet::Parser::Functions newfunction(:foo, doc: <<~'DOC' An example 3.x function. @param [String] first The first parameter. @param second The second parameter. @return [Undef] Returns nothing. DOC ) do |*args| # ... end end SOURCE it 'registers a function object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Functions.instance(PuppetStrings::Yard::CodeObjects::Function::RUBY_3X)) expect(object.name).to eq(:foo) expect(object.signature).to eq('foo(String $first, Any $second)') expect(object.parameters).to eq([['first', nil], ['second', nil]]) expect(object.docstring).to eq('An example 3.x function.') expect(object.docstring.tags.size).to eq(4) tags = object.docstring.tags(:param) expect(tags.size).to eq(2) expect(tags[0].name).to eq('first') expect(tags[0].text).to eq('The first parameter.') expect(tags[0].types).to eq(['String']) expect(tags[1].name).to eq('second') expect(tags[1].text).to eq('The second parameter.') expect(tags[1].types).to eq(['Any']) tags = object.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].name).to be_nil expect(tags[0].text).to eq('Returns nothing.') expect(tags[0].types).to eq(['Undef']) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') end end describe 'parsing a function with a missing @return tag' do let(:source) { <<~SOURCE } Puppet::Parser::Functions.newfunction(:foo, doc: <<~'DOC') do |*args| An example 3.x function. @param [String] first The first parameter. @param second The second parameter. DOC # ... end SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing @return tag near \(stdin\):1/).to_stdout_from_any_process end end end describe 'parsing 4.x API functions' do describe 'parsing a function with a missing docstring' do let(:source) { <<~SOURCE } Puppet::Functions.create_function(:foo) do end SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing documentation for Puppet function 'foo' at \(stdin\):1\./).to_stdout_from_any_process end end describe 'parsing a function with a simple docstring' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:foo) do end SOURCE it 'registers a function object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Functions.instance(PuppetStrings::Yard::CodeObjects::Function::RUBY_4X)) expect(object.name).to eq(:foo) expect(object.signature).to eq('foo()') expect(object.parameters).to eq([]) expect(object.docstring).to eq('An example 4.x function.') expect(object.docstring.tags.size).to eq(1) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') end end describe 'parsing a function without any dispatches' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:foo) do # @param [Integer] param1 The first parameter. # @param param2 The second parameter. # @param [String] param3 The third parameter. # @return [Undef] Returns nothing. def foo(param1, param2, param3 = nil) end end SOURCE it 'registers a function object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Functions.instance(PuppetStrings::Yard::CodeObjects::Function::RUBY_4X)) expect(object.name).to eq(:foo) expect(object.signature).to eq('foo(Integer $param1, Any $param2, Optional[String] $param3 = undef)') expect(object.parameters).to eq([['param1', nil], ['param2', nil], %w[param3 undef]]) expect(object.docstring).to eq('An example 4.x function.') expect(object.docstring.tags.size).to eq(5) tags = object.docstring.tags(:param) expect(tags.size).to eq(3) expect(tags[0].name).to eq('param1') expect(tags[0].text).to eq('The first parameter.') expect(tags[0].types).to eq(['Integer']) expect(tags[1].name).to eq('param2') expect(tags[1].text).to eq('The second parameter.') expect(tags[1].types).to eq(['Any']) expect(tags[2].name).to eq('param3') expect(tags[2].text).to eq('The third parameter.') expect(tags[2].types).to eq(['Optional[String]']) tags = object.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].name).to be_nil expect(tags[0].text).to eq('Returns nothing.') expect(tags[0].types).to eq(['Undef']) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') end end describe 'parsing a function with a single dispatch' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:foo) do # @param param1 The first parameter. # @param param2 The second parameter. # @param param3 The third parameter. # @return [Undef] Returns nothing. dispatch :foo do param 'Integer', :param1 param 'Any', :param2 optional_param 'Array[String]', :param3 end def foo(param1, param2, param3 = nil) end end SOURCE it 'registers a function object without any overload tags' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Functions.instance(PuppetStrings::Yard::CodeObjects::Function::RUBY_4X)) expect(object.name).to eq(:foo) expect(object.signature).to eq('foo(Integer $param1, Any $param2, Optional[Array[String]] $param3)') expect(object.parameters).to eq([['param1', nil], ['param2', nil], ['param3', nil]]) expect(object.docstring).to eq('An example 4.x function.') expect(object.docstring.tags(:overload)).to be_empty expect(object.docstring.tags.size).to eq(5) tags = object.docstring.tags(:param) expect(tags.size).to eq(3) expect(tags[0].name).to eq('param1') expect(tags[0].text).to eq('The first parameter.') expect(tags[0].types).to eq(['Integer']) expect(tags[1].name).to eq('param2') expect(tags[1].text).to eq('The second parameter.') expect(tags[1].types).to eq(['Any']) expect(tags[2].name).to eq('param3') expect(tags[2].text).to eq('The third parameter.') expect(tags[2].types).to eq(['Optional[Array[String]]']) tags = object.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].name).to be_nil expect(tags[0].text).to eq('Returns nothing.') expect(tags[0].types).to eq(['Undef']) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') end end describe 'parsing a function using only return_type' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:foo) do # @param param1 The first parameter. # @param param2 The second parameter. # @param param3 The third parameter. dispatch :foo do param 'Integer', :param1 param 'Any', :param2 optional_param 'Array[String]', :param3 return_type 'String' end def foo(param1, param2, param3 = nil) "Bar" end end SOURCE it 'does not throw an error with no @return' do expect { spec_subject }.not_to raise_error end it 'contains a return data type' do tags = spec_subject.first.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].name).to be_nil expect(tags[0].types).to eq(['String']) end end describe 'parsing a function with various dispatch parameters.' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:foo) do # @param param1 The first parameter. # @param param2 The second parameter. # @param param3 The third parameter. # @param param4 The fourth parameter. # @return [Undef] Returns nothing. dispatch :foo do param 'String', :param1 required_param 'Integer', :param2 optional_param 'Array', :param3 repeated_param 'String', :param4 end end SOURCE it 'registers a function object with the expected parameters' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Functions.instance(PuppetStrings::Yard::CodeObjects::Function::RUBY_4X)) expect(object.name).to eq(:foo) expect(object.signature).to eq('foo(String $param1, Integer $param2, Optional[Array] $param3, String *$param4)') expect(object.parameters).to eq([['param1', nil], ['param2', nil], ['param3', nil], ['*param4', nil]]) expect(object.docstring).to eq('An example 4.x function.') expect(object.docstring.tags(:overload)).to be_empty expect(object.docstring.tags.size).to eq(6) tags = object.docstring.tags(:param) expect(tags.size).to eq(4) expect(tags[0].name).to eq('param1') expect(tags[0].text).to eq('The first parameter.') expect(tags[0].types).to eq(['String']) expect(tags[1].name).to eq('param2') expect(tags[1].text).to eq('The second parameter.') expect(tags[1].types).to eq(['Integer']) expect(tags[2].name).to eq('param3') expect(tags[2].text).to eq('The third parameter.') expect(tags[2].types).to eq(['Optional[Array]']) expect(tags[3].name).to eq('*param4') expect(tags[3].text).to eq('The fourth parameter.') expect(tags[3].types).to eq(['String']) tags = object.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].name).to be_nil expect(tags[0].text).to eq('Returns nothing.') expect(tags[0].types).to eq(['Undef']) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') end end describe 'parsing a function with an optional repeated param.' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:foo) do # @param param The first parameter. # @return [Undef] Returns nothing. dispatch :foo do optional_repeated_param 'String', :param end end SOURCE it 'registers a function object with the expected parameters' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Functions.instance(PuppetStrings::Yard::CodeObjects::Function::RUBY_4X)) expect(object.name).to eq(:foo) expect(object.signature).to eq('foo(Optional[String] *$param)') expect(object.parameters).to eq([['*param', nil]]) expect(object.docstring).to eq('An example 4.x function.') expect(object.docstring.tags(:overload)).to be_empty expect(object.docstring.tags.size).to eq(3) tags = object.docstring.tags(:param) expect(tags.size).to eq(1) expect(tags[0].name).to eq('*param') expect(tags[0].text).to eq('The first parameter.') expect(tags[0].types).to eq(['Optional[String]']) tags = object.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].name).to be_nil expect(tags[0].text).to eq('Returns nothing.') expect(tags[0].types).to eq(['Undef']) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') end end describe 'parsing a function with a block param with one parameter' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:foo) do # @param a_block The block parameter. # @return [Undef] Returns nothing. dispatch :foo do block_param :a_block end end SOURCE it 'registers a function object with the expected parameters' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Functions.instance(PuppetStrings::Yard::CodeObjects::Function::RUBY_4X)) expect(object.name).to eq(:foo) expect(object.signature).to eq('foo(Callable &$a_block)') expect(object.parameters).to eq([['&a_block', nil]]) expect(object.docstring).to eq('An example 4.x function.') expect(object.docstring.tags(:overload)).to be_empty expect(object.docstring.tags.size).to eq(3) tags = object.docstring.tags(:param) expect(tags.size).to eq(1) expect(tags[0].name).to eq('&a_block') expect(tags[0].text).to eq('The block parameter.') expect(tags[0].types).to eq(['Callable']) tags = object.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].name).to be_nil expect(tags[0].text).to eq('Returns nothing.') expect(tags[0].types).to eq(['Undef']) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') end end describe 'parsing a function with a block param with two parameter' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:foo) do # @param a_block The block parameter. # @return [Undef] Returns nothing. dispatch :foo do optional_block_param 'Callable[String]', :a_block end end SOURCE it 'registers a function object with the expected parameters' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Functions.instance(PuppetStrings::Yard::CodeObjects::Function::RUBY_4X)) expect(object.name).to eq(:foo) expect(object.signature).to eq('foo(Optional[Callable[String]] &$a_block)') expect(object.parameters).to eq([['&a_block', nil]]) expect(object.docstring).to eq('An example 4.x function.') expect(object.docstring.tags(:overload)).to be_empty expect(object.docstring.tags.size).to eq(3) tags = object.docstring.tags(:param) expect(tags.size).to eq(1) expect(tags[0].name).to eq('&a_block') expect(tags[0].text).to eq('The block parameter.') expect(tags[0].types).to eq(['Optional[Callable[String]]']) tags = object.docstring.tags(:return) expect(tags.size).to eq(1) expect(tags[0].name).to be_nil expect(tags[0].text).to eq('Returns nothing.') expect(tags[0].types).to eq(['Undef']) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') end end end describe 'parsing a function with a multiple dispatches' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:foo) do # The first overload. # @param param1 The first parameter. # @param param2 The second parameter. # @param param3 The third parameter. # @return [Undef] Returns nothing. dispatch :foo do param 'Integer', :param1 param 'Any', :param2 optional_param 'Array[String]', :param3 end # The second overload. # @param param The first parameter. # @param block The block parameter. # @return [String] Returns a string. dispatch :other do param 'Boolean', :param block_param end def foo(param1, param2, param3 = nil) end def other(b) 'lol' end end SOURCE it 'registers a function object with overload tags' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Functions.instance(PuppetStrings::Yard::CodeObjects::Function::RUBY_4X)) expect(object.name).to eq(:foo) expect(object.signature).to eq('') expect(object.parameters).to eq([]) expect(object.docstring).to eq('An example 4.x function.') expect(object.docstring.tags(:param)).to be_empty expect(object.docstring.tags(:return)).to be_empty expect(object.docstring.tags.size).to eq(3) overloads = object.docstring.tags(:overload) expect(overloads.size).to eq(2) expect(overloads[0]).to be_a(PuppetStrings::Yard::Tags::OverloadTag) expect(overloads[0].docstring).to eq('The first overload.') expect(overloads[0].signature).to eq('foo(Integer $param1, Any $param2, Optional[Array[String]] $param3)') expect(overloads[0].tags.size).to eq(4) tags = overloads[0].tags(:param) expect(tags.size).to eq(3) expect(tags[0].name).to eq('param1') expect(tags[0].text).to eq('The first parameter.') expect(tags[0].types).to eq(['Integer']) expect(tags[1].name).to eq('param2') expect(tags[1].text).to eq('The second parameter.') expect(tags[1].types).to eq(['Any']) expect(tags[2].name).to eq('param3') expect(tags[2].text).to eq('The third parameter.') expect(tags[2].types).to eq(['Optional[Array[String]]']) tags = overloads[0].tags(:return) expect(tags.size).to eq(1) expect(tags[0].name).to be_nil expect(tags[0].text).to eq('Returns nothing.') expect(tags[0].types).to eq(['Undef']) expect(overloads[1]).to be_a(PuppetStrings::Yard::Tags::OverloadTag) expect(overloads[1].docstring).to eq('The second overload.') expect(overloads[1].signature).to eq('foo(Boolean $param, Callable &$block)') expect(overloads[1].tags.size).to eq(3) tags = overloads[1].tags(:param) expect(tags.size).to eq(2) expect(tags[0].name).to eq('param') expect(tags[0].text).to eq('The first parameter.') expect(tags[0].types).to eq(['Boolean']) expect(tags[1].name).to eq('&block') expect(tags[1].text).to eq('The block parameter.') expect(tags[1].types).to eq(['Callable']) tags = overloads[1].tags(:return) expect(tags.size).to eq(1) expect(tags[0].name).to be_nil expect(tags[0].text).to eq('Returns a string.') expect(tags[0].types).to eq(['String']) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') end end describe 'parsing a function with a namespaced name' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:'foo::bar::baz') do # @return [Undef] dispatch :foo do end end SOURCE it 'outputs the name correctly as a symbol' do expect(spec_subject.size).to eq(1) expect(spec_subject.first.name).to eq(:'foo::bar::baz') end end describe 'parsing a function with a missing parameter' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:foo) do # @param missing A missing parameter. # @return [Undef] Returns nothing. dispatch :foo do end end SOURCE it 'outputs a warning' do expect { spec_subject }.to output(/\[warn\]: The @param tag for parameter 'missing' has no matching parameter at \(stdin\):5/).to_stdout_from_any_process end end describe 'parsing a function with a missing @param tag' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:foo) do # @return [Undef] Returns nothing. dispatch :foo do param 'String', :param1 end end SOURCE it 'outputs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing @param tag for parameter 'param1' near \(stdin\):5/).to_stdout_from_any_process end end describe 'parsing a function with a typed @param tag' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:foo) do # @param [Integer] param1 The first parameter. # @return [Undef] Returns nothing. dispatch :foo do param 'String', :param1 end end SOURCE it 'outputs a warning' do expect { spec_subject } .to output( /\[warn\]: The @param tag for parameter 'param1' should not contain a type specification near \(stdin\):6: ignoring in favor of dispatch type information\./ ) .to_stdout_from_any_process end end describe 'parsing a function with a typed @param tag' do let(:source) { <<~SOURCE } # An example 4.x function. Puppet::Functions.create_function(:foo) do # @param param1 The first parameter. dispatch :foo do param 'String', :param1 end end SOURCE it 'outputs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing @return tag near \(stdin\):4/).to_stdout_from_any_process end end describe 'parsing a function with a root @param tag' do let(:source) { <<~SOURCE } # An example 4.x function. # @param param Nope. Puppet::Functions.create_function(:foo) do # @return [Undef] dispatch :foo do end end SOURCE it 'outputs a warning' do expect { spec_subject } .to output( /\[warn\]: The docstring for Puppet 4.x function 'foo' contains @param tags near \(stdin\):3: parameter documentation should be made on the dispatch call\./ ) .to_stdout_from_any_process end end describe 'parsing a function with a root @overload tag' do let(:source) { <<~SOURCE } # An example 4.x function. # @overload foo Puppet::Functions.create_function(:foo) do # @return [Undef] dispatch :foo do end end SOURCE it 'outputs a warning' do expect { spec_subject } .to output( /\[warn\]: The docstring for Puppet 4.x function 'foo' contains @overload tags near \(stdin\):3: overload tags are automatically generated from the dispatch calls\./ ) .to_stdout_from_any_process end end describe 'parsing a function with a root @return tag' do let(:source) { <<~SOURCE } # An example 4.x function. # @return [Undef] foo Puppet::Functions.create_function(:foo) do # @return [Undef] dispatch :foo do end end SOURCE it 'outputs a warning' do expect { spec_subject } .to output( /\[warn\]: The docstring for Puppet 4.x function 'foo' contains @return tags near \(stdin\):3: return value documentation should be made on the dispatch call\./ ) .to_stdout_from_any_process end end describe 'parsing a function with a summary' do context 'when the summary has fewer than 140 characters' do let(:source) { <<~SOURCE } # An example 4.x function. # @summary A short summary. Puppet::Functions.create_function(:foo) do # @return [Undef] dispatch :foo do end end SOURCE it 'parses the summary' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) summary = spec_subject.first.tags(:summary) expect(summary.first.text).to eq('A short summary.') end end context 'when the summary has more than 140 characters' do let(:source) { <<~SOURCE } # An example 4.x function. # @summary A short summary that is WAY TOO LONG. AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH this is not what a summary is for! It should be fewer than 140 characters!! Puppet::Functions.create_function(:foo) do # @return [Undef] dispatch :foo do end end SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: The length of the summary for puppet_function 'foo' exceeds the recommended limit of 140 characters./).to_stdout_from_any_process end end end end provider_handler_spec.rb000066400000000000000000000125461466634474300345760ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/ruby# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' describe PuppetStrings::Yard::Handlers::Ruby::ProviderHandler do subject(:spec_subject) do YARD::Parser::SourceParser.parse_string(source, :ruby) YARD::Registry.all(:puppet_provider) end describe 'parsing source without a provider definition' do let(:source) { 'puts "hi"' } it 'no providers should be in the registry' do expect(spec_subject.empty?).to be(true) end end describe 'parsing a provider with a missing description' do let(:source) { <<~SOURCE } Puppet::Type.type(:custom).provide :linux do end SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing a description for Puppet provider 'linux' \(resource type 'custom'\) at \(stdin\):1\./).to_stdout_from_any_process end end describe 'parsing a provider with an invalid docstring assignment' do let(:source) { <<~SOURCE } Puppet::Type.type(:custom).provide :linux do @doc = 123 end SOURCE it 'logs an error' do expect { spec_subject }.to output(/Failed to parse docstring/).to_stdout_from_any_process end end describe 'parsing a provider with a valid docstring assignment' do let(:source) { <<~SOURCE } Puppet::Type.type(:custom).provide :linux do @doc = 'An example provider on Linux.' end SOURCE it 'correctlies detect the docstring' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.docstring).to eq('An example provider on Linux.') end end describe 'parsing a provider with a docstring which uses ruby `%Q` notation' do let(:source) { <<~'SOURCE' } Puppet::Type.type(:custom).provide :linux do test = 'hello world!' desc %Q{This is a multi-line doc in %Q with #{test}} end SOURCE it 'strips the `%Q{}` and render the interpolation expression literally' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.docstring).to eq("This is a multi-line\ndoc in %Q with \#{test}") end end describe 'parsing a provider definition' do let(:source) { <<~SOURCE } Puppet::Type.type(:custom).provide :linux do desc 'An example provider on Linux.' confine kernel: 'Linux' confine osfamily: 'RedHat' defaultfor :kernel => 'Linux' defaultfor :osfamily => 'RedHat', :operatingsystemmajrelease => '7' has_feature :implements_some_feature has_feature :some_other_feature commands foo: '/usr/bin/foo' end SOURCE it 'registers a provider object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Provider) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Providers.instance('custom')) expect(object.name).to eq(:linux) expect(object.type_name).to eq('custom') expect(object.docstring).to eq('An example provider on Linux.') expect(object.docstring.tags.size).to eq(1) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') expect(object.confines).to eq({ 'kernel' => 'Linux', 'osfamily' => 'RedHat' }) expect(object.defaults).to eq([[%w[kernel Linux]], [%w[osfamily RedHat], %w[operatingsystemmajrelease 7]]]) expect(object.features).to eq(%w[implements_some_feature some_other_feature]) expect(object.commands).to eq({ 'foo' => '/usr/bin/foo' }) end end describe 'parsing a provider definition with a string based name' do let(:source) { <<~SOURCE } Puppet::Type.type(:'custom').provide :'linux' do desc 'An example provider on Linux.' end SOURCE it 'registers a provider object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Provider) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Providers.instance('custom')) expect(object.name).to eq(:linux) expect(object.type_name).to eq('custom') expect(object.docstring).to eq('An example provider on Linux.') end end describe 'parsing a provider with a summary' do context 'when the summary has fewer than 140 characters' do let(:source) { <<~SOURCE } Puppet::Type.type(:custom).provide :linux do @doc = '@summary A short summary.' end SOURCE it 'parses the summary' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) summary = spec_subject.first.tags(:summary) expect(summary.first.text).to eq('A short summary.') end end context 'when the summary has more than 140 characters' do let(:source) { <<~SOURCE } Puppet::Type.type(:custom).provide :linux do @doc = '@summary A short summary that is WAY TOO LONG. AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH this is not what a summary is for! It should be fewer than 140 characters!!' end SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: The length of the summary for puppet_provider 'linux' exceeds the recommended limit of 140 characters./).to_stdout_from_any_process end end end end puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/ruby/rsapi_handler_spec.rb000066400000000000000000000216031466634474300341330ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' describe PuppetStrings::Yard::Handlers::Ruby::RsapiHandler do subject(:spec_subject) do YARD::Parser::SourceParser.parse_string(source, :ruby) YARD::Registry.all(:puppet_type) end describe 'parsing source without a type definition' do let(:source) { 'puts "hi"' } it 'no types should be in the registry' do expect(spec_subject.empty?).to be(true) end end describe 'parsing a type with a missing description' do let(:source) { <<~SOURCE } Puppet::ResourceApi.register_type( name: 'database' ) SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing a description for Puppet resource type 'database' at \(stdin\):1\./).to_stdout_from_any_process end end describe 'parsing a type with a valid docstring assignment' do let(:source) { <<~SOURCE } Puppet::ResourceApi.register_type( name: 'database', docs: 'An example database server resource type.', ) SOURCE it 'correctlies detect the docstring' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.docstring).to eq('An example database server resource type.') end end describe 'parsing a type with a docstring which uses ruby `%Q` notation' do let(:source) { <<~'SOURCE' } test = 'hello world!' Puppet::ResourceApi.register_type( name: 'database', docs: %Q{This is a multi-line doc in %Q with #{test}}, ) SOURCE it 'strips the `%Q{}` and render the interpolation expression literally' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.docstring).to eq("This is a multi-line\ndoc in %Q with \#{test}") end end describe 'parsing a type definition' do let(:source) { <<~SOURCE } # @!puppet.type.param [value1, value2] dynamic_param Documentation for a dynamic parameter. # @!puppet.type.property [foo, bar] dynamic_prop Documentation for a dynamic property. Puppet::ResourceApi.register_type( name: 'database', docs: 'An example database server resource type.', features: ['remote-resource'], attributes: { ensure: { type: 'Enum[present, absent, up, down]', desc: 'What state the database should be in.', default: 'up', }, address: { type: 'String', desc: 'The database server name.', behaviour: :namevar, }, encrypt: { type: 'Boolean', desc: 'Whether or not to encrypt the database.', default: false, behaviour: :parameter, }, encryption_key: { type: 'Optional[String]', desc: 'The encryption key to use.', behaviour: :parameter, }, backup: { type: 'Enum[daily, monthly, never]', desc: 'How often to backup the database.', default: 'never', behaviour: :parameter, }, file: { type: 'String', desc: 'The database file to use.', }, log_level: { type: 'Enum[debug, warn, error]', desc: 'The log level to use.', default: 'warn', }, }, ) SOURCE it 'registers a type object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Type) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Types.instance) expect(object.name).to eq(:database) expect(object.docstring).to eq('An example database server resource type.') expect(object.docstring.tags.size).to eq(1) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') expect(object.properties.map(&:name)).to eq(%w[dynamic_prop ensure file log_level]) expect(object.properties.size).to eq(4) expect(object.properties[0].name).to eq('dynamic_prop') expect(object.properties[0].docstring).to eq('Documentation for a dynamic property.') expect(object.properties[0].isnamevar).to be(false) expect(object.properties[0].values).to eq(%w[foo bar]) expect(object.properties[1].name).to eq('ensure') expect(object.properties[1].docstring).to eq('What state the database should be in.') expect(object.properties[1].isnamevar).to be(false) expect(object.properties[1].default).to eq('up') expect(object.properties[1].data_type).to eq('Enum[present, absent, up, down]') expect(object.properties[1].aliases).to eq({}) expect(object.properties[2].name).to eq('file') expect(object.properties[2].docstring).to eq('The database file to use.') expect(object.properties[2].isnamevar).to be(false) expect(object.properties[2].default).to be_nil expect(object.properties[2].data_type).to eq('String') expect(object.properties[2].aliases).to eq({}) expect(object.properties[3].name).to eq('log_level') expect(object.properties[3].docstring).to eq('The log level to use.') expect(object.properties[3].isnamevar).to be(false) expect(object.properties[3].default).to eq('warn') expect(object.properties[3].data_type).to eq('Enum[debug, warn, error]') expect(object.properties[3].aliases).to eq({}) expect(object.parameters.size).to eq(5) expect(object.parameters[0].name).to eq('dynamic_param') expect(object.parameters[0].docstring).to eq('Documentation for a dynamic parameter.') expect(object.parameters[0].isnamevar).to be(false) expect(object.parameters[0].values).to eq(%w[value1 value2]) expect(object.parameters[1].name).to eq('address') expect(object.parameters[1].docstring).to eq('The database server name.') expect(object.parameters[1].isnamevar).to be(true) expect(object.parameters[1].default).to be_nil expect(object.parameters[1].data_type).to eq('String') expect(object.parameters[1].aliases).to eq({}) expect(object.parameters[2].name).to eq('encrypt') expect(object.parameters[2].docstring).to eq('Whether or not to encrypt the database.') expect(object.parameters[2].isnamevar).to be(false) expect(object.parameters[2].default).to be(false) expect(object.parameters[2].data_type).to eq('Boolean') expect(object.parameters[2].aliases).to eq({}) expect(object.parameters[3].name).to eq('encryption_key') expect(object.parameters[3].docstring).to eq('The encryption key to use.') expect(object.parameters[3].isnamevar).to be(false) expect(object.parameters[3].default).to be_nil expect(object.parameters[3].data_type).to eq('Optional[String]') expect(object.parameters[3].aliases).to eq({}) expect(object.parameters[4].name).to eq('backup') expect(object.parameters[4].docstring).to eq('How often to backup the database.') expect(object.parameters[4].isnamevar).to be(false) expect(object.parameters[4].default).to eq('never') expect(object.parameters[4].data_type).to eq('Enum[daily, monthly, never]') end end describe 'parsing a type with a summary' do context 'when the summary has fewer than 140 characters' do let(:source) { <<~SOURCE } Puppet::ResourceApi.register_type( name: 'database', docs: '@summary A short summary.', ) SOURCE it 'parses the summary' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) summary = spec_subject.first.tags(:summary) expect(summary.first.text).to eq('A short summary.') end end context 'when the summary has more than 140 characters' do let(:source) { <<~SOURCE } Puppet::ResourceApi.register_type( name: 'database', docs: '@summary A short summary that is WAY TOO LONG. AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH this is not what a summary is for! It should be fewer than 140 characters!!', ) SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: The length of the summary for puppet_type 'database' exceeds the recommended limit of 140 characters./).to_stdout_from_any_process end end end describe 'parsing a type with title_patterns' do let(:source) { <<~SOURCE } Puppet::ResourceApi.register_type( name: 'database', docs: 'An example database server resource type.', title_patterns: [ { pattern: %r{(?.*)}, desc: 'Generic title match', } ] ) SOURCE it 'does not emit a warning' do expect { spec_subject }.not_to output(/\[warn\].*unexpected construct regexp_literal/).to_stdout_from_any_process end end end type_extras_handler_spec.rb000066400000000000000000000041571466634474300353120ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/ruby# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' describe PuppetStrings::Yard::Handlers::Ruby::TypeExtrasHandler do subject(:spec_subject) do YARD::Parser::SourceParser.parse_string(source, :ruby) YARD::Registry.all(:puppet_type) end describe 'parsing source with newproperty' do let(:source) { <<~SOURCE } Puppet::Type.newtype(:database) do desc 'database' end Puppet::Type.type(:database).newproperty(:file) do desc 'The database file to use.' end SOURCE it 'generates a doc string for a property' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.properties.size).to eq(1) expect(object.properties[0].name).to eq('file') expect(object.properties[0].docstring).to eq('The database file to use.') end end describe 'parsing source with newparam' do let(:source) { <<~SOURCE } Puppet::Type.newtype(:database) do desc 'database' end Puppet::Type.type(:database).newparam(:name) do desc 'The database server name.' end SOURCE it 'generates a doc string for a parameter that is also a namevar' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.parameters.size).to eq(1) expect(object.parameters[0].name).to eq('name') expect(object.parameters[0].docstring).to eq('The database server name.') expect(object.parameters[0].isnamevar).to be(true) end end describe 'parsing source with ensurable' do let(:source) { <<~SOURCE } Puppet::Type.newtype(:database) do desc 'database' end Puppet::Type.type(:database).ensurable do desc 'What state the database should be in.' end SOURCE it 'generates a doc string for an ensurable' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.properties.size).to eq(1) expect(object.properties[0].name).to eq('ensure') expect(object.properties[0].docstring).to eq('What state the database should be in.') end end end puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/handlers/ruby/type_handler_spec.rb000066400000000000000000000276151466634474300340070ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' describe PuppetStrings::Yard::Handlers::Ruby::TypeHandler do subject(:spec_subject) do YARD::Parser::SourceParser.parse_string(source, :ruby) YARD::Registry.all(:puppet_type) end describe 'parsing source without a type definition' do let(:source) { 'puts "hi"' } it 'no types should be in the registry' do expect(spec_subject.empty?).to be(true) end end describe 'parsing a type with a missing description' do let(:source) { <<~SOURCE } Puppet::Type.newtype(:database) do end SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: Missing a description for Puppet resource type 'database' at \(stdin\):1\./).to_stdout_from_any_process end end describe 'parsing a type with an invalid docstring assignment' do let(:source) { <<~SOURCE } Puppet::Type.newtype(:database) do @doc = 123 end SOURCE it 'logs an error' do expect { spec_subject }.to output(/Failed to parse docstring/).to_stdout_from_any_process end end describe 'parsing a type with a valid docstring assignment' do let(:source) { <<~SOURCE } Puppet::Type.newtype(:database) do @doc = 'An example database server resource type.' end SOURCE it 'correctlies detect the docstring' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.docstring).to eq('An example database server resource type.') end end describe 'parsing a type with a docstring which uses ruby `%Q` notation' do let(:source) { <<~'SOURCE' } Puppet::Type.newtype(:database) do test = 'hello world!' desc %Q{This is a multi-line doc in %Q with #{test}} end SOURCE it 'strips the `%Q{}` and render the interpolation expression literally' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.docstring).to eq("This is a multi-line\ndoc in %Q with \#{test}") end end describe 'parsing a type with a param with arguments' do let(:source) { <<~SOURCE } Puppet::Type.newtype(:database) do feature :encryption, 'The provider supports encryption.', methods: [:encrypt] newparam(:encryption_key, :parent => Puppet::Parameter::Boolean, required_features: :encryption) do desc 'The encryption key to use.' defaultto false end end SOURCE it 'correctlies detect the required_feature' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.parameters[0].required_features).to eq('encryption') end it 'correctlies detect a boolean parent' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.parameters[0].default).to eq('false') end end describe 'parsing a type definition' do let(:source) { <<~SOURCE } # @!puppet.type.param [value1, value2] dynamic_param Documentation for a dynamic parameter. # @!puppet.type.property [foo, bar] dynamic_prop Documentation for a dynamic property. Puppet::Type.newtype(:database) do desc 'An example database server resource type.' feature :encryption, 'The provider supports encryption.', methods: [:encrypt] feature :magic, 'The feature docstring should have whitespace and newlines stripped out.' ensurable do desc 'What state the database should be in.' defaultvalues aliasvalue(:up, :present) aliasvalue(:down, :absent) defaultto :up end newparam(:address) do isnamevar desc 'The database server name.' end newparam(:encryption_key, required_features: :encryption) do desc 'The encryption key to use.' end newparam(:encrypt, :parent => Puppet::Parameter::Boolean) do desc 'Whether or not to encrypt the database.' defaultto false end newparam(:backup) do desc 'How often to backup the database.' defaultto :never newvalues(:daily, :monthly, :never) end newproperty(:file) do desc 'The database file to use.' end newproperty(:log_level) do desc 'The log level to use.' newvalue(:debug) newvalue(:warn) newvalue(:error) defaultto 'warn' end end SOURCE it 'registers a type object' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Type) expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::Types.instance) expect(object.name).to eq(:database) expect(object.docstring).to eq('An example database server resource type.') expect(object.docstring.tags.size).to eq(1) tags = object.docstring.tags(:api) expect(tags.size).to eq(1) expect(tags[0].text).to eq('public') expect(object.properties.size).to eq(4) expect(object.properties[0].name).to eq('dynamic_prop') expect(object.properties[0].docstring).to eq('Documentation for a dynamic property.') expect(object.properties[0].isnamevar).to be(false) expect(object.properties[0].values).to eq(%w[foo bar]) expect(object.properties[1].name).to eq('ensure') expect(object.properties[1].docstring).to eq('What state the database should be in.') expect(object.properties[1].isnamevar).to be(false) expect(object.properties[1].default).to eq('up') expect(object.properties[1].values).to eq(%w[present absent up down]) expect(object.properties[1].aliases).to eq({ 'down' => 'absent', 'up' => 'present' }) expect(object.properties[2].name).to eq('file') expect(object.properties[2].docstring).to eq('The database file to use.') expect(object.properties[2].isnamevar).to be(false) expect(object.properties[2].default).to be_nil expect(object.properties[2].values).to eq([]) expect(object.properties[2].aliases).to eq({}) expect(object.properties[3].name).to eq('log_level') expect(object.properties[3].docstring).to eq('The log level to use.') expect(object.properties[3].isnamevar).to be(false) expect(object.properties[3].default).to eq('warn') expect(object.properties[3].values).to eq(%w[debug warn error]) expect(object.properties[3].aliases).to eq({}) expect(object.parameters.size).to eq(5) expect(object.parameters[0].name).to eq('dynamic_param') expect(object.parameters[0].docstring).to eq('Documentation for a dynamic parameter.') expect(object.parameters[0].isnamevar).to be(false) expect(object.parameters[0].values).to eq(%w[value1 value2]) expect(object.parameters[1].name).to eq('address') expect(object.parameters[1].docstring).to eq('The database server name.') expect(object.parameters[1].isnamevar).to be(true) expect(object.parameters[1].default).to be_nil expect(object.parameters[1].values).to eq([]) expect(object.parameters[1].aliases).to eq({}) expect(object.parameters[2].name).to eq('encryption_key') expect(object.parameters[2].docstring).to eq('The encryption key to use.') expect(object.parameters[2].isnamevar).to be(false) expect(object.parameters[2].default).to be_nil expect(object.parameters[2].values).to eq([]) expect(object.parameters[2].aliases).to eq({}) expect(object.parameters[3].name).to eq('encrypt') expect(object.parameters[3].docstring).to eq('Whether or not to encrypt the database.') expect(object.parameters[3].isnamevar).to be(false) expect(object.parameters[3].default).to eq('false') expect(object.parameters[3].values).to eq(%w[true false yes no]) expect(object.parameters[3].aliases).to eq({}) expect(object.parameters[4].name).to eq('backup') expect(object.parameters[4].docstring).to eq('How often to backup the database.') expect(object.parameters[4].isnamevar).to be(false) expect(object.parameters[4].default).to eq('never') expect(object.parameters[4].values).to eq(%w[daily monthly never]) expect(object.features.size).to eq(2) expect(object.features[0].name).to eq('encryption') expect(object.features[0].docstring).to eq('The provider supports encryption.') expect(object.features[1].name).to eq('magic') expect(object.features[1].docstring).to eq('The feature docstring should have whitespace and newlines stripped out.') end end describe 'parsing a valid type with string based name' do let(:source) { <<~SOURCE } Puppet::Type.newtype(:'database') do desc 'An example database server resource type.' ensurable end SOURCE it 'registers a type object with default ensure values' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.name).to eq(:database) end end describe 'parsing an ensurable type with default ensure values' do let(:source) { <<~SOURCE } Puppet::Type.newtype(:database) do desc 'An example database server resource type.' ensurable end SOURCE it 'registers a type object with default ensure values' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.properties[0].name).to eq('ensure') expect(object.properties[0].docstring).to eq('The basic property that the resource should be in.') expect(object.properties[0].default).to eq('present') expect(object.properties[0].values).to eq(%w[present absent]) end end describe 'parsing a type with a parameter with the name of "name"' do let(:source) { <<~SOURCE } Puppet::Type.newtype(:database) do desc 'An example database server resource type.' newparam(:name) do desc 'The database server name.' end end SOURCE it 'registers a type object with the "name" parameter as the namevar' do expect(spec_subject.size).to eq(1) object = spec_subject.first expect(object.parameters.size).to eq(1) expect(object.parameters[0].name).to eq('name') expect(object.parameters[0].isnamevar).to be(true) end end describe 'parsing a type with a check with the name of "onlyif"' do let(:source) { <<~SOURCE } Puppet::Type.newtype(:testexec) do desc 'An example exec type with a check.' newcheck(:onlyif) do desc 'a test check param' end end SOURCE it 'registers a check object on the parent type object' do expect(spec_subject.size).to eq(1) type_object = spec_subject.first expect(type_object.checks.size).to eq(1) expect(type_object.checks[0].name).to eq('onlyif') end end describe 'parsing a type with a summary' do context 'when the summary has fewer than 140 characters' do let(:source) { <<~SOURCE } Puppet::Type.newtype(:database) do @doc = '@summary A short summary.' end SOURCE it 'parses the summary' do expect { spec_subject }.not_to output.to_stdout_from_any_process expect(spec_subject.size).to eq(1) summary = spec_subject.first.tags(:summary) expect(summary.first.text).to eq('A short summary.') end end context 'when the summary has more than 140 characters' do let(:source) { <<~SOURCE } Puppet::Type.newtype(:database) do @doc = '@summary A short summary that is WAY TOO LONG. AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH this is not what a summary is for! It should be fewer than 140 characters!!' end SOURCE it 'logs a warning' do expect { spec_subject }.to output(/\[warn\]: The length of the summary for puppet_type 'database' exceeds the recommended limit of 140 characters./).to_stdout_from_any_process end end end end puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/parsers/000077500000000000000000000000001466634474300266555ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/parsers/json/000077500000000000000000000000001466634474300276265ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/parsers/json/parser_spec.rb000066400000000000000000000036021466634474300324620ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' describe PuppetStrings::Yard::Parsers::JSON::Parser do subject(:spec_subject) { described_class.new(source, file) } let(:file) { 'test.json' } describe 'initialization of the parser' do let(:source) { '{}' } it 'stores the original source' do expect(spec_subject.source).to eq(source) end it 'stores the original file name' do expect(spec_subject.file).to eq(file) end it 'has no relevant statements' do spec_subject.parse expect(spec_subject.enumerator).to be_empty end end describe 'parsing invalid JSON' do let(:source) { <<~SOURCE } class foo { SOURCE it 'raises an exception' do expect { spec_subject.parse }.to output(/\[error\]: Failed to parse test.json/).to_stdout_from_any_process end end describe 'parsing valid task metadata JSON' do let(:source) { <<~SOURCE } { "description": "Allows you to backup your database to local file.", "input_method": "stdin", "parameters": { "database": { "description": "Database to connect to", "type": "Optional[String[1]]" }, "user": { "description": "The user", "type": "Optional[String[1]]" }, "password": { "description": "The password", "type": "Optional[String[1]]" }, "sql": { "description": "Path to file you want backup to", "type": "String[1]" } } } SOURCE it 'parses the JSON and extract a TaskStatement' do spec_subject.parse expect(spec_subject.enumerator.size).to eq(1) statement = spec_subject.enumerator.first expect(statement).to be_instance_of(PuppetStrings::Yard::Parsers::JSON::TaskStatement) end end end puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/parsers/json/task_statement_spec.rb000066400000000000000000000027661466634474300342260ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' describe PuppetStrings::Yard::Parsers::JSON::TaskStatement do subject(:spec_subject) { described_class.new(json, source, 'test.json') } let(:source) { <<~SOURCE } { "description": "Allows you to backup your database to local file.", "input_method": "stdin", "parameters": { "database": { "description": "Database to connect to", "type": "Optional[String[1]]" }, "user": { "description": "The user", "type": "Optional[String[1]]" }, "password": { "description": "The password", "type": "Optional[String[1]]" }, "sql": { "description": "Path to file you want backup to", "type": "String[1]" } } } SOURCE let(:json) { JSON.parse(source) } describe '#comments' do it 'returns docstring' do expect(spec_subject.comments).to eq 'Allows you to backup your database to local file.' end end describe '#parameters' do context 'with params' do it 'returns params' do expect(!spec_subject.parameters.empty?).to be true end end context 'no params' do let(:source) { <<~SOURCE } { "description": "Allows you to backup your database to local file.", "input_method": "stdin" } SOURCE it 'returns an empty hash' do expect(spec_subject.parameters).to eq({}) end end end end puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/parsers/puppet/000077500000000000000000000000001466634474300301725ustar00rootroot00000000000000puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/parsers/puppet/parser_spec.rb000066400000000000000000000300601466634474300330240ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' describe PuppetStrings::Yard::Parsers::Puppet::Parser do subject(:spec_subject) { described_class.new(source, file) } let(:file) { 'test.pp' } describe 'initialization of the parser' do let(:source) { 'notice hi' } it 'stores the original source' do expect(spec_subject.source).to eq(source) end it 'stores the original file name' do expect(spec_subject.file).to eq(file) end it 'has no relevant statements' do spec_subject.parse expect(spec_subject.enumerator).to be_empty end end describe 'parsing invalid Puppet source code' do let(:source) { <<~SOURCE } class foo { SOURCE it 'raises an exception' do expect { spec_subject.parse }.to output(/\[error\]: Failed to parse test.pp: Syntax error at end of (file|input)/).to_stdout_from_any_process end end describe 'parsing class definitions' do let(:source) { <<~SOURCE } notice hello # A simple foo class. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. class foo(Integer $param1, $param2, String $param3 = hi) inherits foo::bar { file { '/tmp/foo': ensure => present } } SOURCE it 'onlies return the class statement' do spec_subject.parse expect(spec_subject.enumerator.size).to eq(1) statement = spec_subject.enumerator.first expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::ClassStatement) expect(statement.source).to eq("class foo(Integer $param1, $param2, String $param3 = hi) inherits foo::bar {\n file { '/tmp/foo':\n ensure => present\n }\n}") expect(statement.file).to eq(file) expect(statement.line).to eq(6) expect(statement.docstring).to eq('A simple foo class.') expect(statement.name).to eq('foo') expect(statement.parent_class).to eq('foo::bar') expect(statement.parameters.size).to eq(3) expect(statement.parameters[0].name).to eq('param1') expect(statement.parameters[0].type).to eq('Integer') expect(statement.parameters[0].value).to be_nil expect(statement.parameters[1].name).to eq('param2') expect(statement.parameters[1].type).to be_nil expect(statement.parameters[1].value).to be_nil expect(statement.parameters[2].name).to eq('param3') expect(statement.parameters[2].type).to eq('String') expect(statement.parameters[2].value).to eq('hi') end end describe 'parsing nested class definitions' do let(:source) { <<~SOURCE } class foo { class bar { } } SOURCE it 'parses both class statements' do spec_subject.parse expect(spec_subject.enumerator.size).to eq(2) statement = spec_subject.enumerator[0] expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::ClassStatement) expect(statement.name).to eq('foo::bar') expect(statement.parameters.size).to eq(0) statement = spec_subject.enumerator[1] expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::ClassStatement) expect(statement.name).to eq('foo') expect(statement.parameters.size).to eq(0) end end describe 'parsing defined types' do let(:source) { <<~SOURCE } notice hello # A simple foo defined type. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. define foo(Integer $param1, $param2, String $param3 = hi) { file { '/tmp/foo': ensure => present } } SOURCE it 'parses the defined type statement' do spec_subject.parse expect(spec_subject.enumerator.size).to eq(1) statement = spec_subject.enumerator.first expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::DefinedTypeStatement) expect(statement.name).to eq('foo') expect(statement.source).to eq("define foo(Integer $param1, $param2, String $param3 = hi) {\n file { '/tmp/foo':\n ensure => present\n }\n}") expect(statement.file).to eq(file) expect(statement.line).to eq(6) expect(statement.docstring).to eq('A simple foo defined type.') expect(statement.parameters.size).to eq(3) expect(statement.parameters[0].name).to eq('param1') expect(statement.parameters[0].type).to eq('Integer') expect(statement.parameters[0].value).to be_nil expect(statement.parameters[1].name).to eq('param2') expect(statement.parameters[1].type).to be_nil expect(statement.parameters[1].value).to be_nil expect(statement.parameters[2].name).to eq('param3') expect(statement.parameters[2].type).to eq('String') expect(statement.parameters[2].value).to eq('hi') end end describe 'parsing puppet plans', if: TEST_PUPPET_PLANS do # The parsing code actually checks this and sets a global (Puppet[:tasks]). # Plan parsing will fail if it hasn't yet encountered a file under plans/. let(:file) { 'plans/test.pp' } let(:source) { <<~SOURCE } # A simple plan. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. plan plann(String $param1, $param2, Integer $param3 = 1) { } SOURCE it 'parses the puppet plan statement' do spec_subject.parse expect(spec_subject.enumerator.size).to eq(1) statement = spec_subject.enumerator.first expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::PlanStatement) expect(statement.name).to eq('plann') expect(statement.source).to eq(source.sub(/\A.*?\n([^#])/m, '\1').chomp) expect(statement.file).to eq(file) expect(statement.line).to eq(5) expect(statement.docstring).to eq('A simple plan.') expect(statement.parameters.size).to eq(3) expect(statement.parameters[0].name).to eq('param1') expect(statement.parameters[0].type).to eq('String') expect(statement.parameters[0].value).to be_nil expect(statement.parameters[1].name).to eq('param2') expect(statement.parameters[1].type).to be_nil expect(statement.parameters[1].value).to be_nil expect(statement.parameters[2].name).to eq('param3') expect(statement.parameters[2].type).to eq('Integer') expect(statement.parameters[2].value).to eq('1') end end describe 'parsing puppet functions', if: TEST_PUPPET_FUNCTIONS do let(:source) { <<~SOURCE } notice hello # A simple foo function. # @param param1 First param. # @param param2 Second param. # @param param3 Third param. function foo(Integer $param1, $param2, String $param3 = hi) { notice world } SOURCE it 'parses the puppet function statement' do spec_subject.parse expect(spec_subject.enumerator.size).to eq(1) statement = spec_subject.enumerator.first expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::FunctionStatement) expect(statement.name).to eq('foo') expect(statement.source).to eq("function foo(Integer $param1, $param2, String $param3 = hi) {\n notice world\n}") expect(statement.file).to eq(file) expect(statement.line).to eq(6) expect(statement.docstring).to eq('A simple foo function.') expect(statement.parameters.size).to eq(3) expect(statement.parameters[0].name).to eq('param1') expect(statement.parameters[0].type).to eq('Integer') expect(statement.parameters[0].value).to be_nil expect(statement.parameters[1].name).to eq('param2') expect(statement.parameters[1].type).to be_nil expect(statement.parameters[1].value).to be_nil expect(statement.parameters[2].name).to eq('param3') expect(statement.parameters[2].type).to eq('String') expect(statement.parameters[2].value).to eq('hi') end end describe 'parsing puppet functions with return type in defintion', if: TEST_FUNCTION_RETURN_TYPE do let(:source) { <<~SOURCE } # A simple foo function. # @return Returns a string function foo() >> String { notice world } SOURCE it 'parses the puppet function statement' do spec_subject.parse expect(spec_subject.enumerator.size).to eq(1) statement = spec_subject.enumerator.first expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::FunctionStatement) expect(statement.type).to eq('String') end end describe 'parsing puppet functions with complex return types in defintion', if: TEST_FUNCTION_RETURN_TYPE do let(:source) { <<~SOURCE } # A simple foo function. # @return Returns a struct with a hash including one key which must be an integer between 1 and 10. function foo() >> Struct[{'a' => Integer[1, 10]}] { notice world } SOURCE it 'parses the puppet function statement' do spec_subject.parse expect(spec_subject.enumerator.size).to eq(1) statement = spec_subject.enumerator.first expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::FunctionStatement) expect(statement.type).to eq("Struct[{'a' => Integer[1, 10]}]") end end describe 'parsing type alias definitions', if: TEST_PUPPET_DATATYPES do context 'given a type alias on a single line' do let(:source) { <<~SOURCE } # A simple foo type. type Module::Typename = Variant[Stdlib::Windowspath, Stdlib::Unixpath] SOURCE it 'parses the puppet type statement' do spec_subject.parse expect(spec_subject.enumerator.size).to eq(1) statement = spec_subject.enumerator.first expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::DataTypeAliasStatement) expect(statement.docstring).to eq('A simple foo type.') expect(statement.name).to eq('Module::Typename') expect(statement.alias_of).to eq('Variant[Stdlib::Windowspath, Stdlib::Unixpath]') end end context 'given a type alias over multiple lines' do let(:source) { <<~SOURCE } # A multiline foo type # with long docs type OptionsWithoutName = Struct[{ value_type => Optional[ValueType], merge => Optional[MergeType] }] SOURCE it 'parses the puppet type statement' do spec_subject.parse expect(spec_subject.enumerator.size).to eq(1) statement = spec_subject.enumerator.first expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::DataTypeAliasStatement) expect(statement.docstring).to eq("A multiline foo type\nwith long docs") expect(statement.name).to eq('OptionsWithoutName') expect(statement.alias_of).to eq("Struct[{\n value_type => Optional[ValueType],\n merge => Optional[MergeType]\n}]") end end end [ 'undef', 'true', '-1', '0.34', 'bareword', "'single quotes'", '"double quotes"', '[]', '[1]', '{}', '{ a => 1 }', '$param1', '1 + 1', 'func()', '$param1.foo(1)', '$param1.foo($param2 + $param3.bar())' ].each do |value| describe "parsing parameter with #{value} default value" do let(:source) { <<~PUPPET } class foo ( $param1 = #{value}, ) {} PUPPET it 'finds correct value' do spec_subject.parse statement = spec_subject.enumerator.first expect(statement.parameters.size).to eq(1) expect(statement.parameters[0].value).to eq(value) end end end [ '$param1.foo()', "$facts['kernel'] ? { 'Linux' => 'linux', 'Darwin' => 'darwin', default => $facts['kernel'], }" ].each do |value| describe "parsing parameter with #{value} default value" do let(:source) { <<~PUPPET } class foo ( $param1 = #{value}, ) {} PUPPET it 'finds correct value' do skip('Broken by https://tickets.puppetlabs.com/browse/PUP-11632') spec_subject.parse statement = spec_subject.enumerator.first expect(statement.parameters.size).to eq(1) expect(statement.parameters[0].value).to eq(value) end end end end puppetlabs-puppet-strings-a4be216/spec/unit/puppet-strings/yard/util_spec.rb000066400000000000000000000035341466634474300275170ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' require 'puppet-strings/yard' describe PuppetStrings::Yard::Util do subject(:spec_subject) { described_class } describe 'scrub_string' do it 'removes `%Q` and its brackets from a string' do str = '%Q{this is a test string}' expect(spec_subject.scrub_string(str)).to eq('this is a test string') end it 'removes `%q` and its brackets from a string' do str = '%q{this is a test string}' expect(spec_subject.scrub_string(str)).to eq('this is a test string') end it 'does not affect newlines when %Q notation is used' do str = <<~STR %Q{this is a test string} STR expect(spec_subject.scrub_string(str)).to eq("this is\na test string") end it 'does not affect a string which does not use %Q notation' do str = 'this is a test string' expect(spec_subject.scrub_string(str)).to eq('this is a test string') end end describe 'github_to_yard_links' do it 'converts a link correctly' do str = '' expect(spec_subject.github_to_yard_links(str)).to eq('') end it 'leaves other links with hashes alone' do str = '' expect(spec_subject.github_to_yard_links(str)).to eq(str) end it 'leaves plain text alone' do str = ' module-description' expect(spec_subject.github_to_yard_links(str)).to eq(' module-description') end end describe 'ast_to_text' do it 'converts a simple AST correctly' do model = Puppet::Pops::Parser::Parser.new.parse_string('class test {}').model expect(described_class.ast_to_text(model.body)).to eq('class test {}') end end end