### Main Server Entry Point Source: https://github.com/google/fruit/wiki/Tutorial:-Server The main function initializes the server injector and starts the server's run loop. ```cpp // main.cpp #include "server.h" #include "request_dispatcher.h" int main() { Injector injector(getServerComponent); Server* server(injector); server->run(getRequestDispatcherComponent); return 0; } ``` -------------------------------- ### Utility Functions for Server Source: https://github.com/google/fruit/wiki/Tutorial:-Server Provides utility functions for getting the current time and creating Fruit components for requests. ```cpp static string getTime() { time_t now = time(nullptr); tm* localTime = localtime(&now); string result = asctime(localTime); if (result.size() != 0 && result.back() == '\n') { result.pop_back(); } return result; } static fruit::Component getRequestComponent(Request* request) { return fruit::createComponent() .bindInstance(*request); } ``` -------------------------------- ### FooHandler Interface and Component Source: https://github.com/google/fruit/wiki/Tutorial:-Server Defines the abstract FooHandler interface and its Fruit component. FooHandler is responsible for handling requests starting with '/foo/'. It requires Request and ServerContext. ```cpp // foo_handler.h #include "request.h" #include "server_context.h" class FooHandler { public: // Handles a request for a subpath of "/foo/". // The request is injected, no need to pass it directly here.` virtual void handleRequest() = 0; }; fruit::Component, FooHandler> getFooHandlerComponent(); ``` -------------------------------- ### Basic Component Replacement Example Source: https://github.com/google/fruit/wiki/Quick-reference Demonstrates how to replace a component's dependency with a fake implementation for testing purposes. The replacement must be specified before the component is installed. ```cpp fruit::Component getFakeDependencyComponent() {...} fruit::Component getBarComponentWithFakeDependency() { return fruit::createComponent() .replace(getDependencyComponent).with(getFakeDependencyComponent) .install(getBarComponent); } ``` -------------------------------- ### BarHandler Interface and Component Source: https://github.com/google/fruit/wiki/Tutorial:-Server Defines the abstract BarHandler interface and its Fruit component. BarHandler handles requests starting with '/bar/'. It also requires Request and ServerContext. ```cpp // bar_handler.h #include "request.h" #include "server_context.h" class BarHandler { public: // Handles a request for a subpath of "/bar/". // The request is injected, no need to pass it directly here. virtual void handleRequest() = 0; }; fruit::Component, BarHandler> getBarHandlerComponent(); ``` -------------------------------- ### vcpkg Installation for Fruit Source: https://github.com/google/fruit/wiki/Install Commands to install Fruit using vcpkg on Windows. This involves cloning the vcpkg repository, bootstrapping it, integrating it with the system, and then installing the Fruit package. ```bash git clone https://github.com/Microsoft/vcpkg.git cd vcpkg ./bootstrap-vcpkg.sh ./vcpkg integrate install vcpkg install fruit ``` -------------------------------- ### Fruit Hello World Example Source: https://github.com/google/fruit/wiki/Tutorial:-Getting-started This C++ code snippet demonstrates a basic 'Hello World' program using the Fruit dependency injection framework. It defines interfaces for 'Writer' and 'Greeter', provides implementations 'StdoutWriter' and 'GreeterImpl', and configures the dependency injection component to wire them together. The `INJECT` macro is used to mark constructors for injection. ```cpp #include #include class Writer { public: virtual void write(std::string s) = 0; }; class StdoutWriter : public Writer { public: // Like "StdoutWriter() = default;" but also marks this constructor as the one to use for injection. INJECT(StdoutWriter()) = default; virtual void write(std::string s) override { std::cout << s; } }; class Greeter { public: virtual void greet() = 0; }; class GreeterImpl : public Greeter { private: Writer* writer; public: // Like "GreeterImpl(Writer* writer) : ... {...}" but also marks this constructor as the one to use for injection. INJECT(GreeterImpl(Writer* writer)) : writer(writer) { } virtual void greet() override { writer->write("Hello world!\n"); } }; fruit::Component getGreeterComponent() { return fruit::createComponent() .bind() .bind(); } int main() { fruit::Injector injector(getGreeterComponent); Greeter* greeter = injector.get(); greeter->greet(); return 0; } ``` -------------------------------- ### Installing Fruit Source: https://github.com/google/fruit/wiki/Install Command to install Fruit after building it, typically to /usr/local on Linux systems. ```bash sudo make install ``` -------------------------------- ### Fruit Component Declaration and Installation Source: https://github.com/google/fruit/wiki/Quick-reference Demonstrates how to declare a Fruit component with requirements and exposed types, and how to install other components and bind types to satisfy dependencies. It shows the process of composing components and resolving automatic bindings. ```cpp fruit::Component, U1, U2> getU1U2Component(); fruit::Component, T1> getT1Component(); class SomeType : public T2 { public: INJECT(SomeType(T3*)) {...} }; fruit::Component, U1> getU1Component() { return fruit::createComponent() .install(getU1U2Component) // Now U1,U2 are provided, T1,T2,T3 are required .install(getT1Component) // Now U1,U2,T1 are provided, T2,T3 are required .bind(); // Now U1,U2,T1,T2 are provided, // T3,SomeType are required } ``` -------------------------------- ### Server Component Binding Source: https://github.com/google/fruit/wiki/Tutorial:-Server Creates a Fruit component that binds the Server interface to its implementation. ```cpp fruit::Component getServerComponent() { return fruit::createComponent() .bind(); } ``` -------------------------------- ### Installing Multiple Components with Pack Expansion Source: https://github.com/google/fruit/wiki/Quick-reference Explains and demonstrates the use of `installComponentFunctions()` with a pack-expansion expression in Fruit. This feature is useful for installing multiple components generated by a templated function (like `getDefaultConstructorComponent`) for a variadic list of types. Each component function must be wrapped in `fruit::componentFunction`. ```cpp template fruit::Component getDefaultConstructorComponent() { return fruit::createComponent() .registerConstructor(); } template fruit::Component getDefaultConstructorsComponent() { return fruit::createComponent() .installComponentFunctions( fruit::componentFunction(getDefaultConstructorComponent)...); } ``` -------------------------------- ### Request Dispatcher Component with Context Source: https://github.com/google/fruit/wiki/Tutorial:-Server Defines a Fruit component for the RequestDispatcher, including context binding for server operations. ```cpp static fruit::Component, RequestDispatcher> getRequestDispatcherComponentWithContext( fruit::Component, RequestDispatcher>( *getRequestDispatcherComponent)(), ServerContext* serverContext) { return fruit::createComponent() .install(getRequestDispatcherComponent) .bindInstance(*serverContext); ``` -------------------------------- ### RequestDispatcher Implementation (Partial) Source: https://github.com/google/fruit/wiki/Tutorial:-Server Provides a partial implementation of RequestDispatcher. It injects the Request and providers for FooHandler and BarHandler. The full implementation would contain the logic to select and call the correct handler. ```cpp // request_dispatcher.cpp #include "request_dispatcher.h" #include "foo_handler.h" #include "bar_handler.h" class RequestDispatcherImpl : public RequestDispatcher { private: const Request& request; Provider fooHandler; Provider barHandler; public: INJECT(RequestDispatcherImpl( const Request& request, ``` -------------------------------- ### Fruit Multibindings Example Source: https://github.com/google/fruit/wiki/Quick-reference Demonstrates how to add multiple multibindings for a given type using `addMultibinding` and how to retrieve them using `getMultibindings`. ```cpp fruit::Component<> getListenerComponent() { return fruit::createComponent() .addMultibinding() .addMultibinding(); } const std::vector& listeners = injector.getMultibindings(); for (Listener* listener : listeners) { listener->notify(); } ``` -------------------------------- ### Server Context Structure Definition Source: https://github.com/google/fruit/wiki/Tutorial:-Server Defines the ServerContext structure, which holds server-specific information like startup time. This demonstrates how to pass non-request-specific data to handlers. ```cpp // server_context.h struct ServerContext { std::string startupTime; }; ``` -------------------------------- ### FooHandler Implementation Source: https://github.com/google/fruit/wiki/Tutorial:-Server Provides the concrete implementation of FooHandler. FooHandlerImpl injects Request and ServerContext and logs the request details. It's bound to the FooHandler interface using Fruit. ```cpp // foo_handler.cpp #include "foo_handler.h" class FooHandlerImpl : public FooHandler { private: const Request& request; const ServerContext& serverContext; public: INJECT(FooHandlerImpl(const Request& request, const ServerContext& serverContext)) : request(request), serverContext(serverContext) { } void handleRequest() override { cout << "FooHandler handling request on server started at " << serverContext.startupTime << " for path: " << request.path << endl; } }; fruit::Component, FooHandler> getFooHandlerComponent() { return fruit::createComponent() .bind(); } ``` -------------------------------- ### Normalized Component Usage Example Source: https://github.com/google/fruit/wiki/Quick-reference Demonstrates how to use `fruit::NormalizedComponent` to create multiple injectors that share common bindings. This example shows the refactoring of root components and the subsequent construction of normalized components and injectors. ```cpp fruit::Component<...> getRootComponent(...) { return fruit::createComponent() // This contains the bindings common to the group of similar injectors. .install(getSharedComponent, ...) // This contains the bindings specific to this injector. .install(getSpecificComponent, ...); } // Traditional injector construction: // fruit::Injector<...> injector(getRootComponent, ...); // Using NormalizedComponent: fruit::NormalizedComponent, ...> normalized_component(getSharedComponent, ...); fruit::Injector<...> injector(normalized_component, getSpecificComponent, ...); // Example in main: fruit::Component, X> getXComponent(); // Lots of bindings here int main() { fruit::NormalizedComponent, X> normalizedComponent( getXComponent()); for (...) { fruit::Component yComponent = ...; // Few injector-specific bindings Injector injector(normalizedComponent, yComponent); X* x = injector.get(); ... } } ``` -------------------------------- ### CMake Project Setup and Configuration Source: https://github.com/google/fruit/blob/master/CMakeLists.txt This snippet outlines the initial CMake setup for the Fruit project. It defines the minimum required CMake version, project name, and version. It also includes logic for handling Conan builds and setting the C++ standard and required flags. Compiler warnings and build type configurations are also managed here. ```cmake cmake_minimum_required(VERSION 3.2...4.0) project(Fruit VERSION 3.7.1 LANGUAGES CXX) set(FRUIT_IS_BEING_BUILT_BY_CONAN FALSE CACHE BOOL "This is set in Conan builds.") if("${FRUIT_IS_BEING_BUILT_BY_CONAN}") include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) conan_basic_setup() endif() if (POLICY CMP0054) cmake_policy(SET CMP0054 NEW) endif() if ("${CMAKE_CXX_STANDARD}" STREQUAL "") set(CMAKE_CXX_STANDARD 11) endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) # CMake on OSX likes to see this set explicitly, otherwise it outputs a warning. set(CMAKE_MACOSX_RPATH 1) if(NOT "${CMAKE_BUILD_TYPE}" MATCHES "^(Debug|Release|RelWithDebInfo|MinSizeRel)$") message(FATAL_ERROR "Please re-run CMake, specifying -DCMAKE_BUILD_TYPE=Debug , -DCMAKE_BUILD_TYPE=Release , -DCMAKE_BUILD_TYPE=RelWithDebInfo or -DCMAKE_BUILD_TYPE=MinSizeRel .") endif() get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) option(FRUIT_ALLOW_MULTI_CONFIG "Allow multi-configuration generator. If this option is OFF, enforces that a single configuration is used." OFF) if(FRUIT_ALLOW_MULTI_CONFIG) if(isMultiConfig) message(STATUS "${CMAKE_PROJECT_NAME} supports the CMake multi-configuration generator," " but is optimized for the `CMAKE_BUILD_TYPE` specified in the CMake configuration step," " and tests will only work in this configuration.") endif() else() # For backward compatibility, only `CMAKE_BUILD_TYPE` configurations can be # used with the multi-configuration generator. This makes it look like # single-configuration generator. set(CMAKE_CONFIGURATION_TYPES "${CMAKE_BUILD_TYPE}") endif() option(BUILD_SHARED_LIBS "Build shared library" ON) set(FRUIT_ADDITIONAL_CXX_FLAGS "" CACHE STRING "Additional CXX compiler flags." FORCE) set(FRUIT_ADDITIONAL_COMPILE_FLAGS "${FRUIT_ADDITIONAL_CXX_FLAGS}") if(NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "^(GNU|Clang|AppleClang|MSVC)$") message(WARNING "Compiler not officially supported: ${CMAKE_CXX_COMPILER_ID}") # Full list of possible values at https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html . # Major compilers not currently supported: # * "Intel": not supported ATM due to compiler bugs: # - https://software.intel.com/en-us/forums/intel-c-compiler/topic/606048 # - https://software.intel.com/en-us/forums/intel-c-compiler/topic/606049 endif() option(FRUIT_ADD_WNO_UNKNOWN_WARNING_OPTION "Add -Wno-unknown-warning-option to the compiler options for GCC, Clang, ICC and AppleClang" ON) if (${FRUIT_ADD_WNO_UNKNOWN_WARNING_OPTION}) set(FRUIT_NO_UNKNOWN_WARNING_FLAGS -Wno-unknown-warning-option) endif() # Get C++ standard flags. set(FRUIT_CXX_STANDARD_FLAGS ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION}) set(FRUIT_ADDITIONAL_COMPILE_FLAGS_GNU -W -Wall -Wno-missing-braces ${FRUIT_NO_UNKNOWN_WARNING_FLAGS}) set(FRUIT_ADDITIONAL_COMPILE_FLAGS_Clang -W -Wall -Wno-missing-braces ${FRUIT_NO_UNKNOWN_WARNING_FLAGS}) set(FRUIT_ADDITIONAL_COMPILE_FLAGS_Intel -W -Wall -Wno-missing-braces ${FRUIT_NO_UNKNOWN_WARNING_FLAGS}) set(FRUIT_ADDITIONAL_COMPILE_FLAGS_AppleClang -W -Wall -Wno-missing-braces ${FRUIT_NO_UNKNOWN_WARNING_FLAGS}) # TODO: we currently disable the warning C4709 because MSVC emits it even when there is no reason to. Re-enable it when possible. # TODO: the warning C4141 is disabled, because MSVC emits it ("'inline': used more than once") when a function/method is marked with both __forceinline and inline. # TODO: the warning C4714 is disabled, MSVC emits it when it decides not to inline a __forceinline function/method. # The warning C4577 is disabled because we don't need a termination guarantee on exceptions for functions marked with # 'noexcept'. # The warning C4530 is disabled because it's triggered by MSVC's STL. ``` -------------------------------- ### Fruit Injector Get Methods Source: https://github.com/google/fruit/wiki/Quick-reference Shows the various ways to retrieve types from a Fruit injector using the `get()` method, including direct access, pointers, references, and providers. It also covers the specific `get()` methods allowed for constant bindings. ```cpp // For non-constant bindings: injector.get() injector.get() injector.get() injector.get() injector.get() injector.get>() injector.get>() injector.get>() // For constant bindings: injector.get() injector.get() injector.get() injector.get>() ``` -------------------------------- ### BarHandler Implementation Source: https://github.com/google/fruit/wiki/Tutorial:-Server Provides the concrete implementation of BarHandler. BarHandlerImpl injects Request and ServerContext and logs the request details. It's bound to the BarHandler interface using Fruit. ```cpp // bar_handler.cpp #include "bar_handler.h" class BarHandlerImpl : public BarHandler { private: const Request& request; const ServerContext& serverContext; public: INJECT(BarHandlerImpl(const Request& request, const ServerContext& serverContext)) : request(request), serverContext(serverContext) { } void handleRequest() override { cout << "BarHandler handling request on server started at " << serverContext.startupTime << " for path: " << request.path << endl; } }; fruit::Component, BarHandler> getBarHandlerComponent() { return fruit::createComponent() .bind(); } ``` -------------------------------- ### Server Interface and Implementation Source: https://github.com/google/fruit/wiki/Tutorial:-Server Defines the Server interface with a `run` method that accepts a component function for request dispatchers. The ServerImpl class manages server startup, request processing in threads, and graceful shutdown. It utilizes Fruit injectors for managing dependencies during request handling. ```cpp // server.h #include "request.h" #include "server_context.h" #include "request_dispatcher.h" class Server { public: virtual void run(fruit::Component, RequestDispatcher> (*)()) = 0; }; fruit::Component getServerComponent(); // server.cpp #include "server.h" #include "server_context.h" #include "request_dispatcher.h" class ServerImpl : public Server { private: std::vector threads; public: INJECT(ServerImpl()) { } ~ServerImpl() { for (std::thread& t : threads) { t.join(); } } void run(fruit::Component, RequestDispatcher> (*getRequestDispatcherComponent)()) override { ServerContext serverContext; serverContext.startupTime = getTime(); const fruit::NormalizedComponent, RequestDispatcher> requestDispatcherNormalizedComponent( getRequestDispatcherComponentWithContext, getRequestDispatcherComponent, &serverContext); cerr << "Server started." << endl; while (1) { cerr << endl; cerr << "Enter the request (absolute path starting with \"/foo/\" or " << "\"/bar/\"), or an empty line to exit." << endl; Request request; getline(cin, request.path); cerr << "Server received request: " + request.path << endl; if (request.path.empty()) { cerr << "Server received empty line, shutting down." << endl; break; } threads.push_back(std::thread( worker_thread_main, std::ref(requestDispatcherNormalizedComponent), request)); } } private: static void worker_thread_main( const fruit::NormalizedComponent< fruit::Required, RequestDispatcher>& requestDispatcherNormalizedComponent, Request request) { fruit::Injector injector( requestDispatcherNormalizedComponent, getRequestComponent, &request); RequestDispatcher* requestDispatcher(injector); requestDispatcher->handleRequest(); } }; ``` -------------------------------- ### CTest Example for Project Testing Source: https://github.com/google/fruit/blob/master/test_package/CMakeLists.txt This snippet demonstrates how to enable and configure CTest for the Google Fruit project. It shows how to add a test named 'example' that executes the compiled program from its working directory. ```cmake # CTest is a testing tool that can be used to test your project. # enable_testing() # add_test(NAME example # WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin # COMMAND example) ``` -------------------------------- ### Generate Dependency Graphs for Examples Source: https://github.com/google/fruit/blob/master/extras/doc/CMakeLists.txt This CMake code iterates through example directories, generating dependency graphs in DOT format using a bash script and then converting them to PNG images using the dot command. The PNG files are normalized using exiftool. The process depends on the example directory contents and the extract_dependencies.sh script. ```cmake set(EXAMPLE_DIRECTORIES hello_world server scaling_doubles multibindings simple_injection ) foreach(D ${EXAMPLE_DIRECTORIES}) add_custom_command(OUTPUT ${D}-deps.png COMMAND bash < ${CMAKE_CURRENT_SOURCE_DIR}/extract_dependencies.sh > ${CMAKE_CURRENT_BINARY_DIR}/${D}.dot COMMAND dot -Goverlap=prism10000 ${CMAKE_CURRENT_BINARY_DIR}/${D}.dot -Tpng -o ${CMAKE_CURRENT_BINARY_DIR}/${D}-deps.png # This normalizes the PNG files, so that we avoid tracking multiple copies of the same file in the Github wiki repo. COMMAND exiftool -all= -overwrite_original ${CMAKE_CURRENT_BINARY_DIR}/${D}-deps.png WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../examples/${D} DEPENDS ../../examples/${D} extract_dependencies.sh ) add_custom_target(${D}-deps ALL DEPENDS ${D}-deps.png) endforeach(D) ``` -------------------------------- ### Installation Directory Source: https://github.com/google/fruit/blob/master/CMakeLists.txt Installs the Fruit header files to the appropriate system include directory. ```cmake install(DIRECTORY include/fruit/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/fruit FILES_MATCHING PATTERN "*.h") ``` -------------------------------- ### Configuring Fruit Build with Custom Install Prefix Source: https://github.com/google/fruit/wiki/Install Command to configure the Fruit build with CMake, specifying a custom installation directory. ```bash cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr . && make -j ``` -------------------------------- ### Request Structure Definition Source: https://github.com/google/fruit/wiki/Tutorial:-Server Defines the structure for a request, containing a URL path. This is a fundamental data structure for the server. ```cpp // request.h struct Request { std::string path; }; ``` -------------------------------- ### Fruit Injection Scopes Example Source: https://github.com/google/fruit/wiki/Quick-reference Demonstrates how Fruit manages dependencies across different scopes using normalized components and instance binding, mimicking Guice's scope behavior without explicit scope declarations. ```cpp // Outer scope class X { public: INJECT(X()) = default; ... }; fruit::Component getXComponent() { return fruit::createComponent(); } // Middle scope class Y { public: INJECT(Y(X* x)); ... }; fruit::Component, Y> getYComponent() { return fruit::createComponent(); } // Inner scope class Z { public: INJECT(Z(X* x, Y* y)); ... }; fruit::Component, Z> getZComponent() { return fruit::createComponent(); } fruit::Component<> getEmptyComponent() { return fruit::createComponent(); } fruit::Component getXInstanceComponent(X* x) { return fruit::createComponent() .bindInstance(*x); } fruit::Component getXYInstanceComponent(X* x, Y* y) { return fruit::createComponent() .bindInstance(*x) .bindInstance(*y); } fruit::NormalizedComponent outerScopeNormalizedComponent( getXComponent); fruit::NormalizedComponent, Y> middleScopeNormalizedComponent( getYComponent); fruit::NormalizedComponent, Z> innerScopeNormalizedComponent( getZComponent); for (...) { // We want to enter the outer scope here. fruit::Injector outerScopeInjector( outerScopeNormalizedComponent, getEmptyComponent); X* x = outerScopeInjector.get(); for (...) { // We want to enter the middle scope here. fruit::Injector middleScopeInjector( middleScopeNormalizedComponent, getXInstanceComponent, x); Y* y = middleScopeInjector.get(); for (...) { // We want to enter the inner scope here. fruit::Injector innerScopeInjector( innerScopeNormalizedComponent, getXYInstanceComponent, x, y); Z* z = innerScopeInjector.get(); ... } } } ``` -------------------------------- ### RequestDispatcher Interface and Component Source: https://github.com/google/fruit/wiki/Tutorial:-Server Defines the abstract RequestDispatcher interface and its Fruit component. This class is responsible for dispatching incoming requests to the appropriate handler based on the URL. ```cpp // request_dispatcher.h #include "request.h" #include "server_context.h" class RequestDispatcher { public: // Handles the current request. // The request is injected, no need to pass it directly here. virtual void handleRequest() = 0; }; fruit::Component, RequestDispatcher> getRequestDispatcherComponent(); ``` -------------------------------- ### RequestDispatcher Implementation Source: https://github.com/google/fruit/wiki/Tutorial:-Server Implements the RequestDispatcher interface to route requests to appropriate handlers (FooHandler or BarHandler) based on the request path. It uses Fruit Providers to lazily inject handlers, optimizing dependency injection for potentially large handler sets. ```cpp class RequestDispatcherImpl : public RequestDispatcher { public: INJECT( RequestDispatcherImpl( fruit::Provider fooHandler, fruit::Provider barHandler)) : request(request), fooHandler(fooHandler), barHandler(barHandler) { } void handleRequest() override { if (stringStartsWith(request.path, "/foo/")) { fooHandler.get()->handleRequest(); } else if (stringStartsWith(request.path, "/bar/")) { barHandler.get()->handleRequest(); } else { cerr << "Error: no handler found for request path: '" << request.path << "' , ignoring request." << endl; } } private: static bool stringStartsWith(const string& s, const string& candidatePrefix) { return s.compare(0, candidatePrefix.size(), candidatePrefix) == 0; } }; fruit::Component, RequestDispatcher> getRequestDispatcherComponent() { return fruit::createComponent() .bind() .install(getFooHandlerComponent) .install(getBarHandlerComponent); } ``` -------------------------------- ### Binding a Factory without Assisted Arguments Source: https://github.com/google/fruit/wiki/Quick-reference Provides an example of binding a factory for a class (`MyClass`) when no additional assisted arguments are needed. This is achieved by simply binding the class to its implementation (`MyClassImpl`). ```cpp using MyClassFactory = std::function(); fruit::Component getMyClassFactoryComponent() { return fruit::createComponent().bind(); } ``` -------------------------------- ### registerConstructor() Example Source: https://github.com/google/fruit/wiki/Quick-reference Demonstrates using the registerConstructor method to specify the injection constructor for a class when the class definition cannot be modified or for conditional injection. ```cpp class GreeterImpl : public Greeter { private: Writer* writer; public: GreeterImpl(Writer* writer) : writer(writer) { } // ... }; fruit::Component, Greeter> getGreeterComponent() { return fruit::createComponent() .registerConstructor() .bind(); } ``` -------------------------------- ### Chained Component Replacements Source: https://github.com/google/fruit/wiki/Quick-reference Shows how to apply multiple replacements to a component, including replacing a component that itself defines replacements. Replacements can be in any order but must precede the installation. ```cpp fruit::Component getFakeDependencyComponent() {...} fruit::Component getOtherFakeDependencyComponent() {...} fruit::Component getBarComponentWithOtherFakeDependency() { return fruit::createComponent() // The two replacements can appear in any order, but they must both be before the install(). .replace(getFakeDependencyComponent).with(getOtherFakeDependencyComponent) .replace(getDependencyComponent).with(getFakeDependencyComponent) .install(getBarComponent); } ``` -------------------------------- ### Composed Incrementer Component Source: https://github.com/google/fruit/wiki/Tutorial:-Simple-system Combines the Incrementer implementation component and the Simple Adder component. It installs both sub-components to create a complete Incrementer provider. ```cpp // simple_incrementer.h #include "incrementer.h" fruit::Component getSimpleIncrementerComponent(); ``` ```cpp // simple_incrementer.cpp #include "simple_incrementer.h" #include "incrementer_impl.h" #include "simple_adder.h" fruit::Component getSimpleIncrementerComponent() { return fruit::createComponent() .install(getIncrementerImplComponent) .install(getSimpleAdderComponent); } ``` -------------------------------- ### Manual Benchmark Execution with Callgrind Source: https://github.com/google/fruit/blob/master/extras/benchmark/README.md Provides a step-by-step guide for manually running Fruit benchmarks, including compilation and profiling with `valgrind`'s `callgrind` tool. This is useful for in-depth performance analysis. ```bash $ cd ~/projects/fruit $ mkdir build $ cd build $ CXX=g++-6 cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo $ make -j 10 $ cd .. $ mkdir generated-benchs $ extras/benchmark/generate_benchmark.py \ --compiler g++-6 \ --fruit-sources-dir ~/projects/fruit \ --fruit-build-dir ~/projects/fruit/build \ --num-components-with-no-deps 10 \ --num-components-with-deps 90 \ --num-deps 10 \ --output-dir generated-benchs \ --generate-debuginfo=true $ cd generated-benchs $ make -j 10 $ valgrind \ --tool=callgrind \ --simulate-cache=yes \ --dump-instr=yes \ ./main 10000 ``` -------------------------------- ### MSVC CMakeSettings.json Configuration (with Boost) Source: https://github.com/google/fruit/wiki/Install Example CMakeSettings.json configuration for Visual Studio 2017 on Windows to build Fruit with Boost. It specifies the generator, build type, build root, and CMake arguments including the Boost directory. ```json { "configurations": [ { "name": "x64-Release", "generator": "Visual Studio 15 2017 Win64", "configurationType": "Release", "buildRoot": "${env.LOCALAPPDATA}\CMakeBuild\${workspaceHash}\build\${name}", "cmakeCommandArgs": "-DBOOST_DIR=C:\\boost\\boost_1_62_0 -DCMAKE_BUILD_TYPE=Release", "buildCommandArgs": "-m -v:minimal" } ] } ``` -------------------------------- ### Lazy Injection with fruit::Provider Source: https://github.com/google/fruit/wiki/Quick-reference Demonstrates how to use `fruit::Provider` to defer the injection of a dependency `T` until it's explicitly requested via the `get()` method. This is useful for dependencies that are expensive to construct or initialize, improving performance when those dependencies are not always needed. ```cpp class Bar { public: INJECT(Bar(ReallyExpensiveClass x, SomeOtherReallyExpensiveClass y)); ... }; class Foo { private: fruit::Provider barProvider; public: INJECT(Foo(fruit::Provider barProvider)) : barProvider(barProvider) { } void doSomething() { Bar* bar = barProvider.get(); ... } }; ``` -------------------------------- ### Templated Component Creation Source: https://github.com/google/fruit/wiki/Quick-reference Shows how to create templated component functions in Fruit. This allows for the creation of generic components that can be instantiated with different types, promoting code reusability and flexibility. The example defines a templated `FooInterface` and `FooImpl`, and a templated function `getFooComponent` to create a component binding them. ```cpp template class FooInterface { ... }; template class FooImpl : public FooInterface> { public: INJECT(FooImpl()) = default; ... }; template fruit::Component> getFooComponent() { return createComponent() .bind>, FooImpl>(); } ``` -------------------------------- ### Scaler Component Interface and Implementation with Assisted Injection Source: https://github.com/google/fruit/wiki/Tutorial:-Assisted-injection Defines the Scaler interface and its factory. The ScalerImpl uses assisted injection (`ASSISTED`) to receive a scaling factor, and it depends on the Multiplier component. The `getScalerComponent` function creates a Fruit component for the Scaler factory, installing the Multiplier component. ```cpp // scaler.h #include "multiplier.h" #include #include class Scaler { public: virtual double scale(double x) = 0; }; using ScalerFactory = std::function(double)>; fruit::Component getScalerComponent(); ``` ```cpp // scaler.cpp #include "scaler.h" #include "multiplier.h" class ScalerImpl : public Scaler { private: Multiplier* multiplier; double factor; public: INJECT(ScalerImpl(ASSISTED(double) factor, Multiplier* multiplier)) : multiplier(multiplier), factor(factor) { } double scale(double x) override { return multiplier->multiply(x, factor); } }; fruit::Component getScalerComponent() { return fruit::createComponent() .bind() .install(getMultiplierComponent()); } ``` -------------------------------- ### Parametrized Component Creation with Conditional Injection Source: https://github.com/google/fruit/wiki/Quick-reference Illustrates how to create parametrized component functions in Fruit, allowing components to be configured based on runtime parameters. The example demonstrates conditional injection by selecting between `OldFooImpl` and `NewFooImpl` based on a boolean flag. It also outlines the requirements for parameter types (copy-constructible, move-constructible, assignable, etc.). ```cpp class FooInterface { ... }; class OldFooImpl : public FooInterface { public: INJECT(OldFooImpl()) = default; ... }; class NewFooImpl : public FooInterface { public: INJECT(NewFooImpl()) = default; ... }; fruit::Component getFooComponent(bool use_old_impl) { if (use_old_impl) { return fruit::createComponent() .bind(); } else { return fruit::createComponent() .bind(); } } ``` -------------------------------- ### Install Fruit Configuration Header Source: https://github.com/google/fruit/blob/master/configuration/CMakeLists.txt Installs the fruit-config-base.h header file from the build directory to the system include directory for the fruit library. This is a CMake command used during the build and installation process. ```cmake install(FILES ${CMAKE_CURRENT_BINARY_DIR}/../include/fruit/impl/fruit-config-base.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/fruit/impl) ``` -------------------------------- ### Subdirectory Inclusion Source: https://github.com/google/fruit/blob/master/CMakeLists.txt Includes subdirectories for configuration, source code, examples, tests, and extras. Examples are excluded from 'make all' in non-debug builds. ```cmake include(GNUInstallDirs) add_subdirectory(configuration) add_subdirectory(src) if(NOT "${FRUIT_IS_BEING_BUILT_BY_CONAN}") if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") # Do not exclude these from "make all" in debug mode, they must build. add_subdirectory(examples) add_subdirectory(tests) else() add_subdirectory(examples EXCLUDE_FROM_ALL) add_subdirectory(tests) endif() add_subdirectory(extras EXCLUDE_FROM_ALL) endif() ``` -------------------------------- ### Install Python Packages for Fruit Testing Source: https://github.com/google/fruit/blob/master/CONTRIBUTING.md Commands to install the necessary Python packages for running Fruit tests using pip. These packages include `absl-py`, `pytest`, and `pytest-xdist` for parallel test execution. ```bash pip install absl-py pip install pytest pip install pytest-xdist ``` -------------------------------- ### Configuring and Building Fruit with MSVC (Windows) Source: https://github.com/google/fruit/wiki/Install Commands to configure and build the Fruit project using CMake and MSVC on Windows. Requires specifying the BOOST_DIR if Boost is used. ```powershell cmake -DCMAKE_BUILD_TYPE=Release -DBOOST_DIR=C:\boost\boost_1_62_0 . msbuild ALL_BUILD.vcxproj ``` -------------------------------- ### Basic Injector Creation Source: https://github.com/google/fruit/wiki/Tutorial:-Testing Demonstrates the creation of a Fruit injector for a Greeter component. This is the fundamental way to set up dependency injection with Fruit. ```cpp fruit::Injector> createInjector() { return fruit::Injector>(getMainComponent); } ``` -------------------------------- ### Build Greeter Executable with CMake Source: https://github.com/google/fruit/blob/master/examples/testing/CMakeLists.txt This snippet defines the build process for the 'greeter' executable using CMake. It specifies the source files required for compilation and links the executable against the 'fruit' library. A comment indicates a future task to integrate test execution. ```cmake set(GREETER_SOURCES cached_greeter.cpp cached_greeter.h cached.h fake_key_value_storage.cpp fake_key_value_storage.h greeter.cpp greeter.h key_value_storage.cpp key_value_storage.h main.cpp ) add_executable(greeter ${GREETER_SOURCES}) target_link_libraries(greeter fruit) # TODO: run the tests here under CMake (ATM they only run when using Bazel). ``` -------------------------------- ### Main Function Usage Source: https://github.com/google/fruit/wiki/Tutorial:-Simple-system Demonstrates how to use the Fruit injector to obtain an Incrementer instance and perform an increment operation. It includes reading input from stdin and writing output to stdout. ```cpp #include "simple_incrementer.h" int main() { fruit::Injector injector(getSimpleIncrementerComponent); Incrementer* incrementer = injector.get(); int x; std::cin >> x; std::cout << incrementer->increment(x) << std::endl; return 0; } ``` -------------------------------- ### Build Server Executable Source: https://github.com/google/fruit/blob/master/examples/server/CMakeLists.txt Defines the build process for the 'server' executable. It lists all source files, adds a preprocessor definition for POSIX threads, and links necessary libraries. ```cmake set(SERVER_SOURCES main.cpp foo_handler.cpp bar_handler.cpp request_dispatcher.cpp server.cpp ) add_definitions("-pthread") add_executable(server ${SERVER_SOURCES}) target_link_libraries(server fruit pthread) ``` -------------------------------- ### Inject Typedef Example 1 Source: https://github.com/google/fruit/wiki/Quick-reference Demonstrates defining an Inject typedef within a class for dependency injection, allowing the constructor signature to be specified directly. ```cpp class GreeterImpl : public Greeter { private: Writer* writer; public: GreeterImpl(Writer* writer) : writer(writer) { } using Inject = GreeterImpl(Writer*); // ... }; class StdoutWriter : public Writer { public: StdoutWriter() = default; // Optional if no other constructors are defined using Inject = StdoutWriter(); // ... }; ``` -------------------------------- ### Fruit Eagerly Inject All Source: https://github.com/google/fruit/wiki/Quick-reference Demonstrates the use of the `eagerlyInjectAll()` method on a Fruit `Injector` to pre-construct all dependencies, enabling thread-safe access to the injector without external synchronization. ```cpp // Assuming 'injector' is an instance of fruit::Injector injector.eagerlyInjectAll(); // Now, 'injector' can be safely shared across multiple threads for get() calls. ``` -------------------------------- ### Inject Typedef Example 2 (Constructor with Default Argument) Source: https://github.com/google/fruit/wiki/Quick-reference Shows how to use Inject typedef with a constructor that has a default argument, illustrating flexibility in defining injection points. ```cpp class StdoutWriter : public Writer { public: StdoutWriter(const char* line_terminator = "\n"); using Inject = StdoutWriter(); // ... }; ``` -------------------------------- ### Main Function to Use the Scaler Component Source: https://github.com/google/fruit/wiki/Tutorial:-Assisted-injection Demonstrates how to use the Fruit injector to obtain a ScalerFactory, create a Scaler instance with a specific factor, and then use the Scaler to perform a scaled multiplication. ```cpp // main.cpp #include "scaler.h" #include int main() { fruit::Injector injector(getScalerComponent); ScalerFactory scalerFactory(injector); std::unique_ptr scaler = scalerFactory(12.1); std::cout << scaler->scale(3) << std::endl; return 0; } ``` -------------------------------- ### Testing with Fruit and Googletest (Not Yet Cached) Source: https://github.com/google/fruit/wiki/Tutorial:-Testing An example of how to test a component managed by Fruit using the googletest framework. This test verifies the initial state of a cached Greeter. ```cpp TEST(CachedGreeter, NotYetCached) { fruit::Injector> injector = createInjector(); Greeter* greeter = injector.get>(); ASSERT_EQ(greeter->greet(), "Hello, world!"); } ``` -------------------------------- ### Brake Interface Definition Source: https://github.com/google/fruit/wiki/Tutorial:-Annotated-injection Defines the base 'Brake' interface with a virtual 'activate' method. This serves as the common interface for different brake implementations. ```cpp // brake.h class Brake { public വല { // Activates the brake. Throws an exception if braking failed. virtual void activate() = 0; }; ``` -------------------------------- ### Using a Factory with Assisted Injection Source: https://github.com/google/fruit/wiki/Quick-reference Shows how to obtain and use a factory function injected by Fruit. The factory is called with an assisted argument to create a new instance of `MyClass`. ```cpp std::function(int)> myClassFactory(injector); std::unique_ptr x = myClassFactory(15); ``` -------------------------------- ### Fruit Startup Time Benchmarks (Clang) Source: https://github.com/google/fruit/wiki/Benchmarks Startup time performance of the Fruit DI framework compared to Boost.DI and Simple DI approaches when compiled with Clang, across scenarios with 100, 250, and 1000 classes. ```benchmark | Startup time (Clang) | 100 classes | 250 classes | 1000 classes | |-------------------------------------|-------------|-------------|--------------| | Fruit | 7.3 ms | 6.6 ms | 9.2 ms | | Boost.DI | 5.7-5.8 ms | 6.2 ms | 8.4 ms | | Simple DI | 5.4 ms | 6.8 ms | 7.1 ms | | Simple DI w/ interfaces | 5.4 ms | 6.2 ms | 6.5 ms | | Simple DI w/ interfaces, new/delete | 5.4 ms | 7 ms | 6.3 ms | ``` -------------------------------- ### Reproduce CI Failures with postsubmit.sh Source: https://github.com/google/fruit/blob/master/CONTRIBUTING.md Example command to reproduce CI failures locally by running the postsubmit.sh script with specific environment variables for OS, compiler, STL, and Ubuntu version. ```bash export OS=linux; export COMPILER='clang-3.9'; export STL='libstdc++'; export UBUNTU='16.04'; extras/scripts/postsubmit.sh DebugValgrind ``` -------------------------------- ### Fruit Compile-Time Error Resolution: Adding INJECT Source: https://github.com/google/fruit/wiki/Tutorial:-Errors Shows how to resolve the `NoBindingFoundError` by adding an `INJECT` macro to the constructor of the type, enabling Fruit to automatically bind it. ```cpp struct X { INJECT(X()) = default; }; fruit::Component getComponent() { return fruit::createComponent(); } ```