marc_bot 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b554d620d2e9958dbd0911ccff5232df5ef37f15fa6395d71ae3984f42f7a7fe
4
+ data.tar.gz: 496241156b3cb4913573fd12bdcd6b12d9d47456303ae03b925d2a9d7f928b01
5
+ SHA512:
6
+ metadata.gz: 664d05078912b06e07ce7aac508a295ee87753450df541bcccc51404e2190c221202e01b723c36ac730849c9b9e56b3e540250c077212df8985c42973b956c88
7
+ data.tar.gz: 18e9d92aca1226b69ff1065231e2b5a24312e35251b09b6f6b14c5b026d18af65751c1a26603d11e9c29147c73c0a217de93ce52ebdd65f342b91291b407abd7
@@ -0,0 +1,18 @@
1
+ name: Ruby
2
+
3
+ on: [push,pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v2
10
+ - name: Set up Ruby
11
+ uses: ruby/setup-ruby@v1
12
+ with:
13
+ ruby-version: 2.7.3
14
+ bundler-cache: true
15
+ - name: Run standard Ruby check
16
+ run: bundle exec standardrb
17
+ - name: Run the spec tests
18
+ run: bundle exec rake
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in marc-bot.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rspec", "~> 3.0"
data/Gemfile.lock ADDED
@@ -0,0 +1,95 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ marc_bot (0.1.0)
5
+ marc (~> 1.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ast (2.4.2)
11
+ coderay (1.1.3)
12
+ concurrent-ruby (1.1.9)
13
+ diff-lcs (1.4.4)
14
+ docile (1.4.0)
15
+ faker (2.18.0)
16
+ i18n (>= 1.6, < 2)
17
+ i18n (1.8.10)
18
+ concurrent-ruby (~> 1.0)
19
+ marc (1.1.1)
20
+ rexml
21
+ scrub_rb (>= 1.0.1, < 2)
22
+ unf
23
+ method_source (1.0.0)
24
+ parallel (1.20.1)
25
+ parser (3.0.1.1)
26
+ ast (~> 2.4.1)
27
+ pry (0.14.1)
28
+ coderay (~> 1.1)
29
+ method_source (~> 1.0)
30
+ rainbow (3.0.0)
31
+ rake (13.0.3)
32
+ regexp_parser (2.1.1)
33
+ rexml (3.2.5)
34
+ rspec (3.10.0)
35
+ rspec-core (~> 3.10.0)
36
+ rspec-expectations (~> 3.10.0)
37
+ rspec-mocks (~> 3.10.0)
38
+ rspec-core (3.10.1)
39
+ rspec-support (~> 3.10.0)
40
+ rspec-expectations (3.10.1)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.10.0)
43
+ rspec-its (1.3.0)
44
+ rspec-core (>= 3.0.0)
45
+ rspec-expectations (>= 3.0.0)
46
+ rspec-mocks (3.10.2)
47
+ diff-lcs (>= 1.2.0, < 2.0)
48
+ rspec-support (~> 3.10.0)
49
+ rspec-support (3.10.2)
50
+ rubocop (1.17.0)
51
+ parallel (~> 1.10)
52
+ parser (>= 3.0.0.0)
53
+ rainbow (>= 2.2.2, < 4.0)
54
+ regexp_parser (>= 1.8, < 3.0)
55
+ rexml
56
+ rubocop-ast (>= 1.7.0, < 2.0)
57
+ ruby-progressbar (~> 1.7)
58
+ unicode-display_width (>= 1.4.0, < 3.0)
59
+ rubocop-ast (1.7.0)
60
+ parser (>= 3.0.1.1)
61
+ rubocop-performance (1.11.2)
62
+ rubocop (>= 1.7.0, < 2.0)
63
+ rubocop-ast (>= 0.4.0)
64
+ ruby-progressbar (1.11.0)
65
+ scrub_rb (1.0.1)
66
+ simplecov (0.21.2)
67
+ docile (~> 1.1)
68
+ simplecov-html (~> 0.11)
69
+ simplecov_json_formatter (~> 0.1)
70
+ simplecov-html (0.12.3)
71
+ simplecov_json_formatter (0.1.3)
72
+ standard (1.1.2)
73
+ rubocop (= 1.17.0)
74
+ rubocop-performance (= 1.11.2)
75
+ unf (0.1.4)
76
+ unf_ext
77
+ unf_ext (0.0.7.7)
78
+ unicode-display_width (2.0.0)
79
+
80
+ PLATFORMS
81
+ x86_64-darwin-20
82
+ x86_64-linux
83
+
84
+ DEPENDENCIES
85
+ faker
86
+ marc_bot!
87
+ pry
88
+ rake (~> 13.0)
89
+ rspec (~> 3.0)
90
+ rspec-its
91
+ simplecov
92
+ standard (~> 1.1)
93
+
94
+ BUNDLED WITH
95
+ 2.2.20
data/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # MarcBot
2
+
3
+ A MARC record generator inspired by [FactoryBot](https://github.com/thoughtbot/factory_bot).
4
+ Use it to create sample MARC records for testing your applications.
5
+
6
+ Note: This is in a very alpha state. Comments, architecture suggestions, and feature requests are all welcome
7
+
8
+ ## Setup
9
+
10
+ Add the gem to you Gemfile. You'll probably only want this in your dev and test environments. And, while you're at
11
+ it, why don't you add Faker too?
12
+
13
+ Add this line to your application's Gemfile
14
+
15
+ ``` ruby
16
+ group :development, :test do
17
+ gem 'faker'
18
+ gem 'marc_bot'
19
+ end
20
+ ```
21
+
22
+ And then execute:
23
+
24
+ bundle install
25
+
26
+ Or install the gem directly:
27
+
28
+ gem install marc_bot
29
+
30
+ ### Usage with RSpec
31
+
32
+ If you're running this in a test suite, such as RSpec, you'll need to initialize your factory definitions:
33
+
34
+ ``` ruby
35
+ require 'faker'
36
+ require 'marc_bot'
37
+
38
+ RSpec.configure do |config|
39
+ config.before(:suite) do
40
+ MarcBot.reload
41
+ end
42
+ end
43
+ ```
44
+
45
+ ## Usage
46
+
47
+ Create a directory to store all of you different factory definitions. Borrowing from FactoryBot, these directories
48
+ are:
49
+
50
+ * records
51
+ * test/records
52
+ * spec/records
53
+
54
+ Create a file in one of those directories--it can have any name, so long as it ends in `.rb`--and
55
+ define a factory for a given kind of record you'd like to create and assign its values:
56
+
57
+ ``` ruby
58
+ MarcBot.define do
59
+ factory :book do
60
+ f008 { "191003s2020 maua b 001 0 eng d"
61
+ f100 { "Thomas, David" }
62
+ f245 do
63
+ {
64
+ a: "The pragmatic programmer :",
65
+ b: "your journey to mastery /",
66
+ c: "Dave Thomas, Andy Hunt."
67
+ }
68
+ end
69
+ end
70
+ end
71
+ ```
72
+
73
+ Then call-up the factory when you need it:
74
+
75
+ ``` ruby
76
+ book = MarcBot.build(:book)
77
+ ```
78
+
79
+ You can also pass in additional fields at build time:
80
+
81
+ ``` ruby
82
+ book = MarcBot.build(:book, f949: { a: "QA76.6.T4494 2020", w: "LC" })
83
+ ```
84
+
85
+ ### Syntax
86
+
87
+ All tagged fields should be prefaced with an "f", although technically, any non-numeric set of letters is fine. We're
88
+ just looking for three numbers. If no subfield is specified, `$a` is assumed.
89
+
90
+ ## Development
91
+
92
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can
93
+ also run `bin/console` for an interactive prompt that will allow you to experiment.
94
+
95
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the
96
+ version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version,
97
+ push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
98
+
99
+ ## Contributing
100
+
101
+ Bug reports and pull requests are welcome on GitHub at https://github.com/awead/marc_bot.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "marc_bot"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/marc_bot.rb ADDED
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "marc"
4
+
5
+ module MarcBot
6
+ require "marc_bot/factory"
7
+ require "marc_bot/field_builder"
8
+ require "marc_bot/find_definitions"
9
+ require "marc_bot/registry"
10
+ require "marc_bot/version"
11
+
12
+ class Error < StandardError; end
13
+
14
+ class << self
15
+ def define(&block)
16
+ instance_exec(&block)
17
+ end
18
+
19
+ def factory(record_name, &block)
20
+ block ||= ->(result) { result }
21
+ factories.register(record_name, block)
22
+ end
23
+
24
+ def build(record_symbol, **options)
25
+ find_definitions if factories.nil?
26
+
27
+ record_factory = factories.find(record_symbol)
28
+ factory = Factory.new
29
+ factory.instance_exec(&record_factory)
30
+ options.map do |option|
31
+ factory.send(option[0]) { option[1] }
32
+ end
33
+ factory.record
34
+ end
35
+
36
+ def reload
37
+ @factories = nil
38
+ find_definitions
39
+ end
40
+
41
+ def factories
42
+ @factories ||= Registry.new("Factory")
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,21 @@
1
+ module MarcBot
2
+ class Factory
3
+ attr_reader :record
4
+
5
+ def initialize
6
+ @record = MARC::Record.new
7
+ end
8
+
9
+ def method_missing(method, *args, &block)
10
+ if method == :leader
11
+ record.leader = yield
12
+ else
13
+ record.append MarcBot::FieldBuilder.call(method: method, input: yield, args: args)
14
+ end
15
+ end
16
+
17
+ def respond_to_missing?
18
+ super
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,64 @@
1
+ module MarcBot
2
+ class FieldBuilder
3
+ SKIP_KEYS = %i[
4
+ indicator1
5
+ indicator2
6
+ ]
7
+
8
+ def self.call(**args)
9
+ new(args.delete(:method), args.delete(:input), args).fields
10
+ end
11
+
12
+ attr_reader :method, :input
13
+
14
+ def initialize(method, input, options)
15
+ @method = method
16
+ @input = input
17
+ end
18
+
19
+ # @return [MARC::ControlField, MARC::DataField]
20
+ def fields
21
+ if input.is_a?(String)
22
+ data_or_control_field(input)
23
+ elsif input.is_a?(Hash)
24
+ MARC::DataField.new(tag, indicator1, indicator2, *subfield_array)
25
+ else
26
+ raise ArgumentError, "#{input.class} isn't a supported factory type"
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def data_or_control_field(input)
33
+ if MARC::ControlField.control_tag?(tag)
34
+ MARC::ControlField.new(tag, input)
35
+ else
36
+ MARC::DataField.new(tag, "0", " ", ["a", input])
37
+ end
38
+ end
39
+
40
+ def subfield_array
41
+ input
42
+ .reject { |key, _value| SKIP_KEYS.include?(key) }
43
+ .to_a
44
+ .map { |subfield| subfield.map(&:to_s) }
45
+ end
46
+
47
+ def tag
48
+ @tag ||= begin
49
+ result = method.to_s.match(/\d{3}/).to_s
50
+ raise MarcBot::Error, "could not determine tag for :#{method}" if result == ""
51
+
52
+ result
53
+ end
54
+ end
55
+
56
+ def indicator1
57
+ input.fetch(:indicator1, "0")
58
+ end
59
+
60
+ def indicator2
61
+ input.fetch(:indicator2, " ")
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,27 @@
1
+ # @note Shamelessly copied from
2
+ # https://github.com/thoughtbot/factory_bot/blob/master/lib/factory_bot/find_definitions.rb
3
+ module MarcBot
4
+ class << self
5
+ # An Array of strings specifying locations that should be searched for MARC record definitions. By default, marc_bot
6
+ # will attempt to require "records", "test/records" and "spec/records". Only the first existing file will be loaded.
7
+ attr_accessor :definition_file_paths
8
+ end
9
+
10
+ self.definition_file_paths = %w[records test/records spec/records]
11
+
12
+ def self.find_definitions
13
+ absolute_definition_file_paths = definition_file_paths.map { |path|
14
+ File.expand_path(path)
15
+ }
16
+
17
+ absolute_definition_file_paths.uniq.each do |path|
18
+ load("{path}.rb") if File.exist?("{path}.rb")
19
+
20
+ if File.directory? path
21
+ Dir[File.join(path, "**", "*.rb")].sort.each do |file|
22
+ load file
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ module MarcBot
2
+ class Registry
3
+ include Enumerable
4
+
5
+ attr_reader :name
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ @items = {}
10
+ end
11
+
12
+ def clear
13
+ items.clear
14
+ end
15
+
16
+ def find(name)
17
+ items[name] || raise(Error, "item :#{name} does not exist in the registry. Did you define it?")
18
+ end
19
+ alias_method :[], :find
20
+
21
+ def register(name, item)
22
+ items[name] = item
23
+ end
24
+
25
+ def registered?(name)
26
+ items.key?(name)
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :items
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarcBot
4
+ VERSION = "0.1.0"
5
+ end
data/marc_bot.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/marc_bot/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "marc_bot"
7
+ spec.version = MarcBot::VERSION
8
+ spec.authors = ["Adam Wead"]
9
+ spec.email = ["awead@users.noreply.github.com"]
10
+
11
+ spec.summary = "A MARC record generator used for testing library systems"
12
+ spec.description = "Uses FactorBot-style syntax to generate MARC records with various random content in them."
13
+ spec.homepage = "https://github.com/awead/marc_bot"
14
+ spec.required_ruby_version = ">= 2.4.0"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = spec.homepage
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
23
+ end
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_dependency "marc", "~> 1.1"
29
+
30
+ spec.add_development_dependency "faker"
31
+ spec.add_development_dependency "pry"
32
+ spec.add_development_dependency "simplecov"
33
+ spec.add_development_dependency "standard", "~> 1.1"
34
+ spec.add_development_dependency "rspec", "~> 3.10"
35
+ spec.add_development_dependency "rspec-its"
36
+ end
metadata ADDED
@@ -0,0 +1,159 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: marc_bot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Wead
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-06-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: marc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faker
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: standard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.10'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.10'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec-its
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Uses FactorBot-style syntax to generate MARC records with various random
112
+ content in them.
113
+ email:
114
+ - awead@users.noreply.github.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".github/workflows/main.yml"
120
+ - ".gitignore"
121
+ - ".rspec"
122
+ - Gemfile
123
+ - Gemfile.lock
124
+ - README.md
125
+ - Rakefile
126
+ - bin/console
127
+ - bin/setup
128
+ - lib/marc_bot.rb
129
+ - lib/marc_bot/factory.rb
130
+ - lib/marc_bot/field_builder.rb
131
+ - lib/marc_bot/find_definitions.rb
132
+ - lib/marc_bot/registry.rb
133
+ - lib/marc_bot/version.rb
134
+ - marc_bot.gemspec
135
+ homepage: https://github.com/awead/marc_bot
136
+ licenses: []
137
+ metadata:
138
+ homepage_uri: https://github.com/awead/marc_bot
139
+ source_code_uri: https://github.com/awead/marc_bot
140
+ post_install_message:
141
+ rdoc_options: []
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: 2.4.0
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ requirements: []
155
+ rubygems_version: 3.2.20
156
+ signing_key:
157
+ specification_version: 4
158
+ summary: A MARC record generator used for testing library systems
159
+ test_files: []