Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Dogfooding #13

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions bin/manifold
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

lib_path = File.expand_path("../lib", Dir.pwd)
$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
lib_path = File.expand_path("../lib", __dir__)
puts lib_path
$LOAD_PATH.unshift lib_path

require "manifold/cli"
require "manifold"

Manifold::CLI.start(ARGV)
1 change: 1 addition & 0 deletions lib/manifold.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require "pathname"
require "thor"
require "yaml"
require "logger"

Dir[File.join(__dir__, "manifold", "**", "*.rb")].sort.each do |file|
require file
Expand Down
21 changes: 11 additions & 10 deletions lib/manifold/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ module Manifold
# CLI provides command line interface functionality
# for creating and managing umbrella projects for data management.
class CLI < Thor
attr_accessor :logger, :bq_service
attr_accessor :logger, :bq_service, :project

def initialize(*args, logger: Logger.new($stdout))
def initialize(*args, logger: Logger.new($stdout),
project: Manifold::API::Project.new(config: DEFAULT_PROJECT_CONFIG))
super(*args)

self.project = project
self.bq_service = Services::BigQueryService.new(logger)
self.logger = logger
logger.level = Logger::INFO

self.bq_service = Services::BigQueryService.new(logger)
end

desc "init NAME", "Generate a new umbrella project for data management"
def init(name)
Manifold::API::Project.create(name)
logger.info "Created umbrella project '#{name}' with projects and vectors directories."
desc "init PROJECT_NAME", "Initializes a new project within the current directory"
def init
project.create
logger.info "Created new project manifold in #{project.directory}."
end

desc "vectors SUBCOMMAND ...ARGS", "Manage vectors"
Expand All @@ -33,15 +34,15 @@ def initialize(*args, logger: Logger.new($stdout))
end

desc "add VECTOR_NAME", "Add a new vector configuration"
def add(name, project: API::Project.new(File.basename(Dir.getwd)))
def add(name)
vector = API::Vector.new(name, project: project)
vector.add
logger.info "Created vector configuration for '#{name}'."
end
}

desc "add WORKSPACE_NAME", "Add a new workspace to a project"
def add(name, project: API::Project.new(File.basename(Dir.getwd)))
def add(name)
workspace = API::Workspace.new(name, project: project)
workspace.add
logger.info "Added workspace '#{name}' with tables and routines directories."
Expand Down
34 changes: 25 additions & 9 deletions lib/manifold/project/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,23 @@ module Manifold
module API
# Projects API
class Project
attr_reader :name, :directory
DEFAULT_CONFIG = {
name: File.basename(Dir.getwd)
}

def initialize(name, directory: Pathname.pwd.join(name))
self.name = name
self.directory = Pathname(directory)
attr_reader :config_path

def initialize(config: Pathname.pwd.join("project.yaml"))
self.config_path = config
end

def create
File.open(config_path, "w") { |file| file.write DEFAULT_CONFIG.to_yaml }
[workspaces_directory, vectors_directory].each(&:mkpath)
end

def self.create(name, directory: Pathname.pwd.join(name))
new(name, directory: directory).tap do |project|
[project.workspaces_directory, project.vectors_directory].each(&:mkpath)
end
def directory
Pathname.new(Dir.pwd)
end

def workspaces_directory
Expand All @@ -25,9 +31,19 @@ def vectors_directory
directory.join("vectors")
end

def created?
File.exist? config_path
end

def config
return nil unless created?

@config ||= YAML.safe_load_file(config_path, permitted_classes: [Symbol])
end

private

attr_writer :name, :directory
attr_writer :config_path
end
end
end
2 changes: 1 addition & 1 deletion lib/manifold/project/workspace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Workspace

DEFAULT_TEMPLATE_PATH = Pathname.pwd.join(
"lib", "manifold", "templates", "workspace_template.yml"
)
).freeze

def initialize(name, project:, template_path: DEFAULT_TEMPLATE_PATH)
self.name = name
Expand Down
50 changes: 28 additions & 22 deletions spec/manifold/api/project_spec.rb
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
# frozen_string_literal: true

RSpec.describe Manifold::API::Project do
RSpec.describe(Manifold::API::Project) do
include FakeFS::SpecHelpers

subject(:project) { described_class.new(name) }
subject(:project) { described_class.new(config: config) }

let(:name) { "wetland" }
let(:config) { Pathname.pwd.join("project.yaml") }

it { is_expected.to have_attributes(name: name) }
it { is_expected.to have_attributes(config_path: config) }

describe ".create" do
before { described_class.create(name) }

it "creates the vectors directory" do
expect(project.vectors_directory).to be_directory
end

it "creates the workspaces directory" do
expect(project.workspaces_directory).to be_directory
end
describe ".directory" do
it { expect(project.directory).to be_an_instance_of(Pathname) }
end

describe ".workspaces_directory" do
Expand All @@ -29,19 +21,33 @@
it { expect(project.vectors_directory).to be_an_instance_of(Pathname) }
end

context "with directory" do
subject(:project) { described_class.new(name, directory: directory) }
context "when not created" do
describe ".created?" do
it { expect(project.created?).to be false }
end

describe ".config" do
it { expect(project.config).to be nil }
end

describe ".create" do
before { project.create }

let(:directory) { Pathname.pwd.join("supplied_directory") }
it { expect(project.config_path).to be_file }
it { expect(project.vectors_directory).to be_directory }
it { expect(project.workspaces_directory).to be_directory }
end
end

it { is_expected.to have_attributes(directory: directory) }
context "when created" do
before { project.create }

it "uses it as the base for the vectors directory" do
expect(project.vectors_directory).to eq directory.join("vectors")
describe ".created?" do
it { expect(project.created?).to be true }
end

it "uses it as the base for the workspaces directory" do
expect(project.workspaces_directory).to eq directory.join("workspaces")
describe ".config" do
it { expect(project.config).to be_a(Hash) }
end
end
end
113 changes: 38 additions & 75 deletions spec/manifold/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,97 +2,60 @@

RSpec.describe Manifold::CLI do
include FakeFS::SpecHelpers
subject(:cli) { described_class.new(logger: logger, project: project) }

let(:null_logger) { instance_double(Logger) }
let(:mock_project) { instance_double(Manifold::API::Project) }
let(:mock_workspace) { instance_double(Manifold::API::Workspace) }
let(:mock_vector) { instance_double(Manifold::API::Vector) }
let(:project) { Manifold::API::Project.new }
let(:logger) { Logger.new(IO::NULL) }

before do
allow(Manifold::API::Project).to receive(:new).and_return(mock_project)
allow(Manifold::API::Workspace).to receive(:new).and_return(mock_workspace)
allow(Manifold::API::Vector).to receive(:new).and_return(mock_vector)
allow(null_logger).to receive(:info)
allow(null_logger).to receive(:level=)
end

describe "#init" do
subject(:cli) { described_class.new(logger: null_logger) }

let(:project_name) { "wetland" }

context "when initializing a new project" do
before do
allow(Manifold::API::Project).to receive(:create).and_return(mock_project)
end
# let(:null_logger) { instance_double(Logger) }
# let(:mock_project) { instance_double(Manifold::API::Project) }
# let(:mock_workspace) { instance_double(Manifold::API::Workspace) }
# let(:mock_vector) { instance_double(Manifold::API::Vector) }

it "creates a new project through the API" do
cli.init(project_name)
expect(Manifold::API::Project).to have_received(:create).with(project_name)
end
# before do
# allow(Manifold::API::Project).to receive(:new).and_return(mock_project)
# allow(Manifold::API::Workspace).to receive(:new).and_return(mock_workspace)
# allow(Manifold::API::Vector).to receive(:new).and_return(mock_vector)
# allow(null_logger).to receive(:info)
# allow(null_logger).to receive(:level=)
# end

it "logs the project creation" do
cli.init(project_name)
expect(null_logger).to have_received(:info)
.with("Created umbrella project '#{project_name}' with projects and vectors directories.")
end
describe "#init" do
before do
allow(project).to receive(:create)
allow(logger).to receive(:info)
cli.init
end

it { expect(project).to have_received(:create) }
it { expect(logger).to have_received(:info) }
end

describe "#add" do
subject(:cli) { described_class.new(logger: null_logger) }

let(:workspace_name) { "Commerce" }

context "when adding a workspace" do
before do
allow(mock_workspace).to receive(:add)
cli.add(workspace_name)
end

it "instantiates a new workspace through the API" do
expect(Manifold::API::Workspace).to have_received(:new)
.with(workspace_name, project: mock_project)
end
let(:name) { "workspace_name" }
let(:workspace) { Manifold::API::Workspace.new(name, project: project) }

it "adds the workspace through the API" do
expect(mock_workspace).to have_received(:add)
end

it "logs the workspace creation" do
expect(null_logger).to have_received(:info)
.with("Added workspace '#{workspace_name}' with tables and routines directories.")
end
before do
allow(workspace).to receive(:add)
cli.add(name)
end
end

describe "vectors#add" do
subject(:cli) do
subcommands = described_class.new.class.subcommand_classes
subcommands["vectors"].new(logger: null_logger)
end
it { expect(workspace).to have_received(:add) }
it { expect(logger).to have_received(:info) }
end

let(:vector_name) { "page" }
describe "vector subcommand" do
let(:name) { "vector_name" }
let(:vector) { Manifold::API::Vector.new(name, project: project) }

context "when adding a vector" do
describe "#add" do
before do
allow(mock_vector).to receive(:add)
cli.add(vector_name)
end

it "instantiates a new vector through the API" do
expect(Manifold::API::Vector).to have_received(:new)
.with(vector_name, project: mock_project)
allow(vector).to receive(:add)
cli.add(name)
end

it "adds the vector through the API" do
expect(mock_vector).to have_received(:add)
end

it "logs the vector creation" do
expect(null_logger).to have_received(:info)
.with("Created vector configuration for '#{vector_name}'.")
end
it { expect(vector).to have_received(:add) }
it { expect(logger).to have_received(:info) }
end
end
end
Loading