diff --git a/exe/gold_miner b/exe/gold_miner index d731e14..6fa7bca 100755 --- a/exe/gold_miner +++ b/exe/gold_miner @@ -3,26 +3,32 @@ $LOAD_PATH.unshift("#{__dir__}/../lib") require "gold_miner" +require "dotenv" -def debug(msg) - return if ENV["DEBUG"].nil? +def load_env_file + Dotenv.load! + Dry::Monads::Success() +rescue Errno::ENOENT + Dry::Monads::Failure("Could not load env file #{env_file.inspect}") +end - puts "[DEBUG] #{msg}" +def prepare + load_env_file + .bind { GoldMiner::Slack::Client.build(api_token: ENV["SLACK_API_TOKEN"]) } + .fmap { |slack_client| + GoldMiner::SlackExplorer.new(slack_client, GoldMiner::AuthorConfig.default) + } end channel = ARGV.first || "dev" -t0 = Time.now - -GoldMiner - .mine_in(channel) - .fmap { |gold_container| - debug "Found #{gold_container.gold_nuggets.size} messages in #{Time.now - t0} seconds." - - blog_post = GoldMiner.smith_blog_post(gold_container) - GoldMiner.distribute(blog_post) - } +prepare.bind { |slack_explorer| + GoldMiner + .new( + explorer: slack_explorer, + smith: GoldMiner::BlogPostSmith.new, + distributor: GoldMiner::TerminalDistributor.new + ) + .mine(channel, start_on: GoldMiner::Helpers::Time.last_friday) +} .or { |error| abort "[ERROR] #{error}" } - -puts -debug "Done in #{Time.now - t0} seconds." diff --git a/lib/gold_miner.rb b/lib/gold_miner.rb index b9e3dbd..0ecfa91 100644 --- a/lib/gold_miner.rb +++ b/lib/gold_miner.rb @@ -1,38 +1,38 @@ # frozen_string_literal: true -require "dotenv" +require "dry/monads" require "zeitwerk" require "openai" Zeitwerk::Loader.for_gem.setup class GoldMiner - class << self - def mine_in(slack_channel, slack_client: GoldMiner::Slack::Client, env_file: ".env") - Dotenv.load!(env_file) + include Dry::Monads[:result] - prepare(slack_client) - .fmap { |client| explore(slack_channel, client) } - end + def initialize(explorer:, smith:, distributor:, env_file: ".env") + @explorer = explorer + @smith = smith + @distributor = distributor + @env_file = env_file + end - def smith_blog_post(gold_container, ...) - BlogPostSmith.new(...).smith(gold_container) - end + def mine(location, start_on:) + explore(location, start_on:) + .bind { |gold_container| smith(gold_container) } + .bind { |blog_post| distribute(blog_post) } + end - def distribute(blog_post) - TerminalDistributor.new.distribute(blog_post) - end + private - private + def explore(location, start_on:) + Success(@explorer.explore(location, start_on:)) + end - def prepare(slack_client) - slack_client.build(api_token: ENV["SLACK_API_TOKEN"]) - end + def smith(gold_container) + Success(@smith.smith(gold_container)) + end - def explore(slack_channel, slack_client) - SlackExplorer - .new(slack_client, AuthorConfig.default) - .explore(slack_channel, start_on: Helpers::Time.last_friday) - end + def distribute(blog_post) + Success(@distributor.distribute(blog_post)) end end diff --git a/lib/gold_miner/slack/client.rb b/lib/gold_miner/slack/client.rb index 25122d0..93a0392 100644 --- a/lib/gold_miner/slack/client.rb +++ b/lib/gold_miner/slack/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require "dry/monads" require "slack-ruby-client" class GoldMiner diff --git a/spec/gold_miner_spec.rb b/spec/gold_miner_spec.rb index 71112d9..89e95dd 100644 --- a/spec/gold_miner_spec.rb +++ b/spec/gold_miner_spec.rb @@ -1,100 +1,28 @@ # frozen_string_literal: true -require "dry-monads" +require "dry/monads" +require "dotenv" RSpec.describe GoldMiner do include Dry::Monads[:result] - describe ".mine_in" do - it "loads the API token from the given env file" do - slack_client_builder = spy("Slack::Client builder") - - GoldMiner.mine_in("dev", slack_client: slack_client_builder, env_file: "./spec/fixtures/.env.test") - - expect(slack_client_builder).to have_received(:build).with(api_token: "test-token") - end - - it "returns interesting messages from the given channel" do - message_author = TestFactories.create_slack_user - slack_message = TestFactories.create_slack_message(user: message_author) - search_result = [slack_message] - - slack_client = instance_double(GoldMiner::Slack::Client, search_messages: search_result) - slack_client_builder = double(GoldMiner::Slack::Client, build: Success(slack_client)) - - result = GoldMiner.mine_in("dev", slack_client: slack_client_builder, env_file: "./spec/fixtures/.env.test") - gold_nuggets = result.value!.gold_nuggets - - expect(gold_nuggets).to eq [ - TestFactories.create_gold_nugget( - content: slack_message.text, - author: TestFactories.create_author( - id: message_author.username, - name: message_author.name, - link: "#to-do" - ), - source: slack_message.permalink - ) - ] - end - end - - describe ".smith_blog_post" do - it "creates a blog post from a gold container" do - date = "2022-10-07" - travel_to date do - with_env("OPEN_AI_API_TOKEN" => nil) do - channel = "dev" - gold_nuggets = [ - TestFactories.create_gold_nugget, - TestFactories.create_gold_nugget - ] - blog_post_class = spy("BlogPost class") - container = TestFactories.create_gold_container( - gold_nuggets: gold_nuggets, - origin: channel, - packing_date: Date.today - ) - GoldMiner.smith_blog_post(container, blog_post_class:) - - expect(blog_post_class).to have_received(:new).with( - slack_channel: channel, - gold_nuggets: gold_nuggets, - since: Date.parse(date), - writer: instance_of(GoldMiner::BlogPost::SimpleWriter) - ) - end - end - end - - context "when the OPEN_AI_API_TOKEN is set" do - it "uses the OpenAiWriter" do - date = "2022-10-07" - token = "test-token" - travel_to date do - with_env("OPEN_AI_API_TOKEN" => token) do - channel = "dev" - gold_nuggets = [ - TestFactories.create_gold_nugget, - TestFactories.create_gold_nugget - ] - blog_post_class = spy("BlogPost class") - container = TestFactories.create_gold_container( - gold_nuggets: gold_nuggets, - origin: channel, - packing_date: Date.today - ) - GoldMiner.smith_blog_post(container, blog_post_class:) - - expect(blog_post_class).to have_received(:new).with( - slack_channel: channel, - gold_nuggets: gold_nuggets, - since: Date.parse(date), - writer: instance_of(GoldMiner::BlogPost::OpenAiWriter) - ) - end - end - end + describe "#mine" do + it "explores, smiths and distributes gold from the given location and date" do + location = "dev" + start_date = Date.parse("2023-10-20") + gold_container = TestFactories.create_gold_container + explorer = spy("Explorer", explore: gold_container) + blog_post = TestFactories.create_blog_post + smith = spy("Smith", smith: blog_post) + distributor = spy("Distributor", distribute: nil) + + gold_miner = GoldMiner.new(explorer: explorer, smith: smith, distributor: distributor) + result = gold_miner.mine(location, start_on: start_date) + + expect(explorer).to have_received(:explore).with(location, start_on: start_date) + expect(smith).to have_received(:smith).with(gold_container) + expect(distributor).to have_received(:distribute).with(blog_post) + expect(result).to be_success end end diff --git a/spec/support/test_factories.rb b/spec/support/test_factories.rb index 520a9a2..cdb6883 100644 --- a/spec/support/test_factories.rb +++ b/spec/support/test_factories.rb @@ -28,6 +28,16 @@ def create_gold_nugget(overriden_attributes = {}) GoldMiner::GoldNugget.new(**default_attributes.merge(overriden_attributes)) end + def create_blog_post(overriden_attributes = {}) + default_attributes = { + slack_channel: "design", + gold_nuggets: [create_gold_nugget], + since: Date.today + } + + GoldMiner::BlogPost.new(**default_attributes.merge(overriden_attributes)) + end + def create_slack_user(overriden_attributes = {}) default_attributes = { id: "U123",